2

我有articles,每篇文章 has_many 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 原则,我宁愿找到另一种方法。

4

2 回答 2

2
  1. 我不会担心 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
于 2013-06-03T23:26:11.623 回答
0

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

我认为您应该能够在不弄乱事务并使用嵌套属性的情况下处理它,如下所示:

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。否则,它将通过嵌套属性分配一个新类别,这将确保如果文章没有其他验证错误,则该类别将保持不变,如果有,则不会保持不变。

于 2017-10-05T19:17:30.400 回答