【问题标题】:Rails hstore and accepts_nested_attributes_for with has_many relation don't stores nested object具有has_many关系的Rails hstore和accepts_nested_attributes_for不存储嵌套对象
【发布时间】:2015-02-13 22:17:19
【问题描述】:

Rails 不希望存储嵌套对象的更改属性。我用:

  • 导轨 4
  • Postgresql 9.3
  • Postgresql 中的 Hstore 列
  • 视图中的嵌套属性
  • 与 rolify gem 一起使用

这里是数据库表:

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"

但没有成功。属性颜色保持“红色”。 有什么想法吗?

【问题讨论】:

  • 不允许的参数? github.com/rails/strong_parameters
  • 您是否尝试重新启动服务器/控制台?另外,尝试使用 bang 方法:保存!更新!在尝试调试时。虽然更新/保存返回 true,但检查记录是否已更改?和/或 .persisted?在那些之后。您还可以检查 postgresql 日志以检查特定事务。
  • 是的,我已经多次重启服务器和控制台。我在日志中看不到更新accounts_roles 表的SQL 语句!就像,rails看不到提交的属性和数据库中的不一样。
  • 不确定是否可能是这种情况,但 .update 可能会在用户对象实际更新时返回 true - 嵌套对象可能不是这种情况?更新后,当您要求 u.account_roles.first.color 时,您并没有访问数据库 - 您正在获取刚刚设置的对象的属性。
  • 在此示例中的u.save 之后(参见控制台示例),我使用u = Account.first 重新加载对象以查看数据库是否有更新。如果我这样做:ar = u.account_roles.first,然后是 ar.color = 'green'ar.save,那么我会看到更新 SQL 转换。这行得通。因此,这不是验证问题。因为它以这种方式工作。但是为什么不能在带有嵌套属性的视图中工作呢?

标签: ruby-on-rails-4 nested-attributes has-many rails-postgresql hstore


【解决方案1】:

解决了问题!我在模型帐户上使用 rolify gem。我决定将定义的 rolify 关联 has_and_belongs_to_many :roles 更改为 has_many :accounts_roleshas_many :roles, through: :accounts_roles。这引发了问题,因为 gem 自己在 gem 中定义了关联。因此,模型定义了两个关联,has_and_belongs_to_many :roleshas_many through。一个钩子解决了这个问题(从模型帐户中删除关联has_many :accounts_roleshas_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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-18
    • 2021-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-22
    • 1970-01-01
    相关资源
    最近更新 更多