rails虚拟属性不会从form_for提交中读取

时间:2012-01-07 19:42:12

标签: ruby-on-rails ruby-on-rails-3 form-for railscasts virtual-attribute

我正在尝试实现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_names不存在,我也无法在现有标签上编辑这些标签。有人可以帮忙吗?

1 个答案:

答案 0 :(得分:1)

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

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

在您的课程中,使用Ruby的attr_writer方法定义您的setter,并将标记名称的字符串(例如"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:将标记名称字符串转换为setter中的Tag个对象

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