Rails hstore и accepts_nested_attributes_for с отношением has_many не хранят вложенный объект

Rails не хочет хранить измененные атрибуты вложенного объекта. Я использую:

  • Рельсы 4
  • PostgreSQL 9.3
  • Столбец Hstore в Postgresql
  • Вложенные атрибуты в представлениях
  • Использование с драгоценным камнем

Здесь таблица базы данных:

create_table :accounts_roles do |t|
  t.references :account, null: false
  t.references :role,    null: false
  t.hstore     :configurations
  t.timestamps
end

Здесь модели:

class Account < ActiveRecord::Base
  has_many :accounts_roles
  has_many :roles, through: :accounts_roles

  accepts_nested_attributes_for :accounts_roles
end

class AccountsRole < ActiveRecord::Base
  belongs_to :account
  belongs_to :role

  store_accessor :configurations, :color
end

Контроллер разрешает все атрибуты для отладки:

def account_params
  params.require(:account).permit!
end

На мой взгляд, я использую fields_for:

<%= form_for @account ... %>
  ...
  <%= f.fields_for :accounts_roles do |ar| %>
    <%= ar.text_field :color ... %>

Если я отправлю форму редактирования, хэш параметра выглядит нормально:

{"utf8"=>"✓", "account"=>{..., "accounts_roles_attributes"=>{"0"=>{"color"=>"green", "id"=>"5"}}},...}

Но цвет не меняется на "зеленый", он остается "красным"!

В консоли rails я попытался выполнить тот же процесс вручную:

> u = Account.first
> u.account_roles.first.color
 => "red"
> u.update(accounts_roles_attributes: { color: "green", id: 5 } )
 => true
> u.account_roles.first.color
 => "green"
> u.save
 => true
> u = Account.first
> u.account_roles.first.color
 => "red"

Но безуспешно. Цвет атрибута остается красным. Есть идеи?


person phlegx    schedule 13.02.2015    source источник
comment
не разрешенный параметр? github.com/rails/strong_parameters   -  person mmln    schedule 14.02.2015
comment
Вы пытались перезапустить сервер/консоль? также попробуйте использовать методы взрыва: сохранить !, обновить! при попытке отладить это. Хотя обновление/сохранение возвращает true, проверьте, изменена ли запись? и/или .persisted? после тех. Вы также можете проверить журналы postgresql для проверки конкретных транзакций.   -  person mmln    schedule 14.02.2015
comment
Да, я много раз перезапускал сервер и консоль. Я не вижу в журнале инструкции SQL, которая обновляет таблицу accounts_roles! Типа, рельсы не видят, что представленный атрибут не такой, как в базе данных.   -  person phlegx    schedule 14.02.2015
comment
не уверен, что это может быть так, но .update может вернуть true, поскольку пользовательский объект действительно обновляется - это может быть не так для вложенных объектов? после обновления, когда вы запрашиваете u.account_roles.first.color, вы не попадаете в базу данных - вы получаете свойство объекта, который вы только что установили.   -  person mmln    schedule 14.02.2015
comment
После u.save в этом примере (см. пример с консолью) я перезагружаю объект с помощью u = Account.first, чтобы проверить, есть ли в базе данных обновление. Если я сделаю: ar = u.account_roles.first, а затем ar.color = 'green' и ar.save, то я увижу переход обновления SQL. Это работает. Таким образом, это не проблема проверки. Потому что это работает таким образом. Но почему не работает в представлении с вложенными атрибутами?   -  person phlegx    schedule 14.02.2015
comment
t.references :role, null: false говорит базе данных не принимать нулевые значения, может быть, вы уже получили недопустимую запись в своей базе данных (отсутствует :role_id)? Вы пытаетесь обновить цвет недопустимой записи (и вы также не передаете :role_id в своем запросе), поэтому в базе данных ничего не сохраняется?   -  person mmln    schedule 14.02.2015
comment
Я удалил все ограничения: проверки, нуль базы данных и т. д., но это не работает. :(   -  person phlegx    schedule 14.02.2015
comment
Давайте продолжим обсуждение в чате.   -  person mmln    schedule 14.02.2015


Ответы (1)


Решил проблему! Я использую rolify gem на модельном аккаунте. Я решил изменить определенную ролевую ассоциацию has_and_belongs_to_many :roles на has_many :accounts_roles и has_many :roles, through: :accounts_roles. Это вызвало проблему, потому что драгоценный камень сам определяет ассоциацию внутри драгоценного камня. Таким образом, в модели были определены обе ассоциации, has_and_belongs_to_many :roles и has_many through. Хук решает проблему (удалить ассоциацию has_many :accounts_roles и has_many :roles, through: :accounts_roles из учетной записи модели).

# config/initializers/hook_rolify.rb
module Rolify
  def rolify(options = {})
    include Role
    extend Dynamic if Rolify.dynamic_shortcuts

    options.reverse_merge!({:role_cname => 'Role'})
    self.role_cname = options[:role_cname]
    self.role_table_name = self.role_cname.tableize.gsub(/\//, "_")

    default_join_table = "#{self.to_s.tableize.gsub(/\//, "_")}_#{self.role_table_name}"
    options.reverse_merge!({:role_join_table_name => default_join_table})
    self.role_join_table_name = options[:role_join_table_name]

    rolify_options = { :class_name => options[:role_cname].camelize }
    # NOTE not needed any more
    # rolify_options.merge!({ :join_table => self.role_join_table_name }) if Rolify.orm == "active_record"
    rolify_options.merge!(options.reject{ |k,v| ![ :before_add, :after_add, :before_remove, :after_remove ].include? k.to_sym })

    # NOTE defining the association has_many through
    # has_and_belongs_to_many :roles, rolify_options
    has_many self.role_join_table_name.to_sym
    has_many :roles, rolify_options.merge!(through: self.role_join_table_name.to_sym)

    self.adapter = Rolify::Adapter::Base.create("role_adapter",  self.role_cname, self.name)
    load_dynamic_methods if Rolify.dynamic_shortcuts
  end
end
person phlegx    schedule 14.02.2015