【问题标题】:rails virtual attributes won't read from form_for submissionrails 虚拟属性不会从 form_for 提交中读取
【发布时间】:2012-01-07 19:42:12
【问题描述】:

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

【问题讨论】:

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


    【解决方案1】:

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

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

    在您的类中,使用 Ruby 的 attr_writer 方法定义您的设置器,并将标签名称字符串(例如 "tag1 tag2 tag3")转换为标签对象,并在保存后回调中将它们保存在数据库中。您还需要一个 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
    

    【讨论】:

    • 嗯,我尝试添加 def tag_names=(value); @tag_names=值;结束,但这没有用。我不知道在那个空间里还能放什么,你觉得呢?
    • 那个分号是不必要的。
    • 顺便说一句,根据经验,Ruby 中的分号是可选的... :)
    • Behrang,我对这个二传手有点困惑。除了 assign_tags 方法之外,我还必须定义这个 setter 吗?为什么 setter 和 assign_tags 有这么多重叠
    • @jay Jay,setter 将字符串转换为Tag 对象,getter 将Tag 对象数组转换为字符串。让我更新我的答案并添加更多详细信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多