Has_many 关联映射到不同的模型

Has_many association mapped to different model

我希望用户能够select他们所说的语言。我已经设置了关联、table 属性和表单的一部分。当我 select 一种语言并提交表单时,我转到 rails 控制台并执行 u.languages 但我得到一个空数组:=> []

这是我提交表单时的日志:

Started POST "/update_user_via_user" for 127.0.0.1 at 2016-03-18 13:26:03 +0200
  ActiveRecord::SchemaMigration Load (0.4ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by UsersController#update_user_via_user as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"CB1Qca0VrBcap9qO6VpKfoi2dG8GNG+tGGNDgCnFEv4E=", "user"=>{ "fullname"=>"John Doe", "languages"=>["", "1", "2"]}, "commit"=>"Save"}
  User Load (28.6ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = 3  ORDER BY "users"."id" ASC LIMIT 1
Unpermitted parameters: languages
   (0.1ms)  begin transaction
   (0.1ms)  commit transaction
Redirected to http://127.0.0.1:3000/setup_profile
Completed 302 Found in 163ms (ActiveRecord: 29.5ms)

现在,如果您仔细查看日志,您会看到 "Unpermitted parameters: languages"。

在我的 users_controller 中,我有以下内容:

  def user_params
    params.require(:user).permit(:languages, :fullname)
  end

和自定义操作:

  def update_user_via_user
    if current_user.update(user_params)
      flash.notice = "Your profile was sent for moderation. We will moderate it asap!"
    else
      flash.alert = "Something went wrong! Please try again."
    end
    redirect_to root_path
  end

其他一些参考:(我的问题在最后)

schema.rb:

语言table:

  create_table "languages", force: true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "user_id"
  end

用户table:

t.string   "languages"

language.rb 型号:

class Language < ActiveRecord::Base
  belongs_to :user
end

和user.rb型号:

class User < ActiveRecord::Base
  has_many :languages
end

观点:

  <%= f.label :languages %>
  <%= f.select :languages, Language.all.map{ |l| [l.name, "#{l.id}"] }, {}, { :multiple => true } %>

我不确定为什么 "languages" 不被允许,也不知道我的代码概念是否正确

class Language < ActiveRecord::Base
  belongs_to :user
end

这会在用户和语言之间建立一对多的关系,这不是您想要的。你想要的是多对多关系:

  • 用户可以说多种语言
  • 语言有很多使用者(用户)

所以为了跟踪这个我们需要第三个 table:

language_users 就是所谓的 join table。实际上,您可以随意命名 table - 将其命名为 a + _ + bs 只是一种约定。

我们还需要设置我们的模型以使用 join table.

class User < ActiveRecord::Base
  has_many :language_users
  has_many :languages, through: :language_users
end

class Language < ActiveRecord::Base
  has_many :language_users
  has_many :users, through: :language_users
end

# this is a join model that links User & Language
class LanguageUser < ActiveRecord::Base
  belongs_to :user
  belongs_to :language
end

要创建用户可以使用 select 种语言的表单元素:

<%= f.collection_select(:languages_ids,  Language.all, :id, :name, multiple: true) %>

或:

<%= f.collection_check_boxes(:languages_ids,  Language.all, :id, :name) %>

languages_ids 是 ActiveRecord 为 has_many 关联创建的一种特殊访问器,它允许您通过传递一个 id 数组将多个关联设置为一个。

我认为 Deep 的答案是正确的,基于 this exchange

我启动了控制台并执行了以下操作:

  irb(main):001:0> x = ActionController::Parameters.new(user: {fullname: "John Doe", languages: ['','1','2']})
  => {"user"=>{"fullname"=>"John Doe", "languages"=>["", "1", "2"]}}

  irb(main):002:0> y = x.require(:user).permit(:fullname, :languages => [])
  => {"fullname"=>"John Doe", "languages"=>["", "1", "2"]}

  irb(main):003:0> y[:languages]
  => ["", "1", "2"]

所以,嗯。

您现在收到的错误消息是什么?和原来一样吗?