Has_many关联映射到不同的模型

时间:2016-03-18 11:41:38

标签: ruby-on-rails associations

我希望用户能够选择他们说的语言。我已经设置了关联,表属性和表单的一部分。当我选择一种语言并提交表单时,我会转到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)

现在,如果仔细观察一下loogs,你会看到“未经许可的参数:语言”。

在我的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:

语言表:

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

用户表:

t.string   "languages"

language.rb model:

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 } %>

我不确定为什么不允许“语言”以及我的代码概念是否正确

2 个答案:

答案 0 :(得分:3)

class Language < ActiveRecord::Base
  belongs_to :user
end

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

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

因此,为了跟踪这一点,我们需要第三个表:

database diagram

language_users就是所谓的连接表。你可以随意命名表格 - 称之为a + _ + bs只是一种约定。

我们还需要设置模型以使用连接表

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

要创建表单元素,用户可以在其中选择要使用的语言:

<%= 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来设置多个关联。

答案 1 :(得分:0)

我认为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"]

所以,嗯。

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