【问题标题】:Rails nested resources: Input vs. output format inconsistencyRails 嵌套资源:输入与输出格式不一致
【发布时间】:2011-05-02 10:44:21
【问题描述】:

给定以下两种模型:

class Company < ActiveRecord::Base
  has_many :departments
  accepts_nested_attributes_for :departments
end

class Department < ActiveRecord::Base
  belongs_to :company
end

我现在可以一次性创建公司及其部门:

@company = Company.create! params[:company]

在此示例中,params[:company] 应如下所示:

params[:company] = {
                     :name => 'Foo Inc',
                     :departments_attributes => {
                       1 => { :name => 'Management' },
                       2 => { :name => 'HR' }
                     }
                   }

注意:departments_attributes 键!

但如果我使用 @company.to_xml 转换为 XML,我会得到以下信息:

<company>
  <id type="integer">1</id>
  <name>Foo Inc</activity>
  <departments type="array">
    <department>
      <id type="integer">1</id>
      <company-id type="integer">1</company-id>
      <name>Management</name>
    </department>
    <department>
      <id type="integer">2</id>
      <company-id type="integer">1</company-id>
      <name>HR</name>
    </department>
  </departments>
</company>

请注意,我在这里将嵌套资源放在名为 &lt;departments&gt; 的容器节点中,而不是 &lt;departments_attributes&gt;

为什么会出现这种不一致?有没有办法让 Rails 接受使用 departments 而不是 departments_attributes 作为包装器的 POST 请求?

在创建 API 时是否只有我认为这很重要?对于非 Rails 的人来说很奇怪,输出也不能用作输入。

你是如何解决这个问题的 - 如果有的话?

【问题讨论】:

    标签: ruby-on-rails xml api rest activerecord


    【解决方案1】:

    这是有充分理由的。当您创建像 has_many :departments 这样的关联时,rails 会为您创建多个方法,包括 departmentsdepartments= 等。

    现在让我们以nested_attributes 为例。我不知道您是否意识到这一点,但是您传递给 params 散列的参数不仅限于属性。它们适用于任何方法。举个例子:

    class Company < ActiveRecord::Base
      def iliketurtles= attrs
        attrs.split(/\s+/).each{|attr| self.send "#{attr}=", 'turtles'}
      end
    
      def iliketurtles
        self.attributes.select{|attr, value| value == 'turtles'}.join(' ')
      end
    end
    

    在本例中,我传递给iliketurtles= 的任何模型属性(作为空格分隔的字符串)都会将这些属性的值设置为“turtles”。调用“Iliketurtles”将为您提供一个以空格分隔的属性字符串,其值等于海龟。这是有趣的部分。我现在可以在我的表单中包含iliketurtles

    <%= f.text_field :iliketurtles %>
    

    或参数,直接:

    params[:company] = {
      :name => 'Foo Inc',
      :iliketurtles => 'description type address'
    }
    

    因此,nested_attributes 所做的就是创建另外两个方法,departments_attributesdepartments_attributes=,基本上是“访问器”或“设置器和获取器”。因此,创建了一些方法来处理嵌套属性。问题是,您不能将这些访问器命名为 departmentsdepartments=,因为这些方法名称已被关联所采用。

    有没有更好的方法来做到这一点?也许吧,但它需要从根本上改变 rails 将参数转换为属性的方式,并且可能会限制开发人员可以做的事情。使用自定义访问器的能力比我的海龟示例让你相信的要强大得多:)

    【讨论】:

    • (该死的在评论中按回车键提交它)...我会添加一个指向包含代码建议的要点的链接,用于将“传入”参数转换为正确的格式:gist.github.com/653925 - 让我知道你的想法! :)
    • 看起来它会起作用,也许你应该考虑滚入 Rails gem :) 我确实发现了一件事,当你导出模型时,你需要在 " 之后添加 ".constantize" .singularize”。否则,它仍然只是一个字符串。
    • 我在字符串周围使用 eval(...) 而不是 .constantize,这也应该可以解决问题 - 没想到。但你的方式似乎更好 - 将修改
    【解决方案2】:

    您总是可以实现departments_attributes 方法,例如:

    def departments_attributes
      departments.map{ |d| d.attributes }
    end
    

    或者类似的...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-29
      相关资源
      最近更新 更多