1

我正在尝试实现 Ryan Bate 的 railscast #167 中概述的 Rails 标记模型。http://railscasts.com/episodes/167-more-on-virtual-attributes

这是一个很棒的系统。但是,我无法获得将 tag_names 提交给控制器的表单。tag_names 的定义是:

 def tag_names
   @tag_names || tags.map(&:name).join(' ')
 end

不幸的是,在我的情况下,@tag_names 从未在表单提交时被分配。我不知道为什么。所以它总是默认为 tags.map(&:name).join(' ')。这意味着我无法创建文章,因为它们的 tag_name 不存在,我也无法在现有标签上编辑这些标签。任何人都可以帮忙吗?

4

1 回答 1

1

简而言之,您的类缺少一个 setter(或者用 Ruby 术语来说,一个属性编写器)。有两种方法可以定义 setter 并处理将空格分隔的标签名称字符串转换为 Tag 对象并将它们持久保存在数据库中。

解决方案 1(Ryan 的解决方案)

在您的类中,使用 Ruby 的attr_writer方法定义您的设置器,并将标签名称字符串(例如"tag1 tag2 tag3")转换为 Tag 对象,并在保存后回调中将它们保存在数据库中。您还需要一个 getter 将Tag文章的对象数组转换为字符串表示形式,其中标签由空格分隔:

class Article << ActiveRecord::Base
  # here we are delcaring the setter
  attr_writer :tag_names

  # here we are asking rails to run the assign_tags method after
  # we save the Article
  after_save :assign_tags

  def tag_names
    @tag_names || tags.map(&:name).join(' ')
  end

  private

  def assign_tags
    if @tag_names
      self.tags = @tag_names.split(/\s+/).map do |name|
        Tag.find_or_create_by_name(name)
      end
    end
  end
end

解决方案2:将标签名称字符串转换为Tagsetter中的对象

class Article << ActiveRecord::Base
  # notice that we are no longer using the after save callback
  # instead, using :autosave => true, we are asking Rails to save
  # the tags for this article when we save the article
  has_many :tags, :through => :taggings, :autosave => true

  # notice that we are no longer using attr_writer
  # and instead we are providing our own setter
  def tag_names=(names)
     self.tags.clear
     names.split(/\s+/).each do |name|
       self.tags.build(:name => name)
     end
  end

  def tag_names
    tags.map(&:name).join(' ')
  end
end
于 2012-01-07T19:47:17.303 回答