在一个事务中分配或创建关联模型



我有articles,每篇文章有许多categories

当用户创建或更新文章时,他或她可以填写类别名称,如果该类别还不存在,则需要创建一个新的类别。

class Article < ActiveRecord::Base
  attr_accessible :category_id, :content, :title, :category_name
  belongs_to :category
  def category_name
    category.try(:name)
  end
  def category_name=(name)
    self.category = Category.find_or_create_by_name(name) if name.present?
  end
end
class Category < ActiveRecord::Base
  attr_accessible :name
  has_many :articles
end
控制器

class ArticlesController < ApplicationController
  load_and_authorize_resource
  respond_to :json
  def create
    @article = Article.create(params[:article])
    respond_with(@article)
  end
  def update
    @article.update_attributes(params[:article])
    @article.save
    respond_with(@article)
  end
  ...
end

createupdate操作上,如果类别尚不存在,则将在单独的事务中创建新的类别。因此,如果article中有错误,无论如何都可以创建一个新类别。

创建/更新操作的日志(为简洁而修剪):

   (0.0ms)  begin transaction
  SQL (0.3ms)  INSERT INTO "categories" ....
   (35.1ms)  commit transaction
   (0.0ms)  begin transaction
  SQL (0.5ms)  INSERT INTO "articles" ...
   (32.2ms)  commit transaction

我希望得到一些建议/解决方案,如何以一种优雅的方式解决这个问题。

我可以在控制器中写
ActiveRecord::Base.transaction do
  @article = Article.create(params[:article])
  respond_with(@article)
end

,但这意味着我必须在两个方法中编写相同的代码:createupdate。因为它违反了DRY原则,我宁愿找到另一种方法。

  1. 我不会关心一行代码是否为DRY。
  2. 你可以这样做

请注意,我不喜欢这样,但这是可行的

def update
  article = Article.find(params[:id])
  article.attributes = params[:article]
  respond_with persist(article)
end
def create
  article = Article.new(params[:article])
  respond_with persist(article)
end
private
def persist(article)
  ActiveRecord::Base.transaction do
    return article.save
  end
end

老问题,但以防有人正在寻找类似问题的解决方案:

我认为你应该能够处理它,而不干扰事务,并使用嵌套属性如下:

class Article < ActiveRecord::Base
  # ...
  belongs_to :category
  accepts_nested_attributes_for :category
  def category_name=(name)
    category = Category.find_by(name: name)
    if category
      self.category_id = category.id
    else
      self.category_attributes = {name: name}
    end
  end
end

如果有那个名称的类别存在,它会分配category_id。否则,它将通过嵌套属性分配一个新类别,该属性将确保在没有其他验证错误的情况下持久化该类别,如果有,则不持久化该类别。

最新更新