Вложенные ресурсы Rails: несоответствие формата ввода и вывода - PullRequest
2 голосов
/ 29 октября 2010

Учитывая следующие две модели:

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!

Но если я преобразую в XML, используя @company.to_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>

Обратите внимание, что здесь я получаю вложенные ресурсы в узле контейнера с именем <departments>, а не <departments_attributes>!

Почему это несоответствие и есть ли способ заставить Rails принимать POST-запрос, используя отделы вместо отдела_attributes в качестве оболочки?

Я единственный, кто считает, что это важно при создании API?Для людей, не относящихся к рельсам, странно, что выходные данные также нельзя использовать в качестве входных данных.

Как вы решили это - если вообще?

Ответы [ 2 ]

4 голосов
/ 29 октября 2010

Для этого есть веская причина. Когда вы создаете ассоциацию типа has_many :departments, rails создает несколько методов для вас, включая departments, departments= и так далее.

Теперь давайте рассмотрим случай 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= (в виде строки, разделенной пробелами), устанавливают значения этих атрибутов как "черепахи". А вызов «Iliketurtles» даст вам строку атрибутов, разделенных пробелами, значение которых равно черепахам. Вот интересная часть. Теперь я могу включить iliketurtles в мои формы:

<%= f.text_field :iliketurtles %>

или параметры напрямую:

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

Итак, что делает nested_attributes, так это создает еще два метода, departments_attributes и departments_attributes=, в основном "accessors" или "setters and getters". Итак, есть методы, созданные для обработки вложенных атрибутов. Проблема в том, что вы не можете назвать эти методы доступа departments и departments=, потому что эти имена методов уже приняты ассоциацией.

Есть ли лучший способ сделать это? Возможно, но это потребует фундаментальных изменений в способе, которым rails преобразует параметры в атрибуты, и может ограничить возможности разработчиков. Возможность использовать пользовательские средства доступа гораздо мощнее, чем мой пример с черепахой, и это заставит вас поверить:)

0 голосов
/ 29 октября 2010

Вы всегда можете реализовать метод departments_attributes, например:

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

или что-то вроде этого ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...