私は現在、これらのモデルでRails 4.2を使用しています:
class User < ActiveRecord::Base
has_many :user_accessories, dependent: :destroy
accepts_nested_attributes_for :user_accessories,
reject_if: :all_blank,
allow_destroy: true
has_many :accessories, through: :user_accessories
end
class UserAccessory < ActiveRecord::Base
belongs_to :user, required: true
belongs_to :accessory, required: true
end
class Accessory < ActiveRecord::Base
has_many :user_accessories, dependent: :destroy
has_many :users, through: :user_accessories
end
これは単純な多対多の関係であり、ユーザーは多くのアクセサリを「所有」でき、アクセサリは多くのユーザーが「所有」できます。
次の方法でルートを設定しました。
resources :users, only: [ :index, :show, :edit, :update, :accessories ] do
member do
get 'accessories'
end
end
このようにして、ユーザーは自分の「アクセサリ」パス ( /users/1/accessories
) に移動してアクセサリのリストを表示したり、アカウントに新しいアクセサリの関連付けを追加したりできます。
アクセサリ パスをレンダリングするビューは次のとおりです。
<table>
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
<%= render @accessories %>
</tbody>
</table>
<%= form_for( @user ) do |f| %>
<%= f.collection_select(
:accessory_ids,
Accessory.all,
:id,
:name, { include_hidden: false }, { multiple: true } )
%>
<%= f.button "Add Equipment" %>
<% end %>
これは、現在のアクセサリのテーブルをレンダリングし、追加する複数のアクセサリを選択できる collection_select ボックスを構築します。Bootstrap スタイルを削除して、これを単純化しました。
最後に、関連するコントローラー アクションを次に示します。
def update
@user = User.find( params[:id] )
if( @user.update_attributes( update_params ) )
redirect_to @user
else
render 'edit'
end
end
def accessories
@user = User.find( params[:id] )
@accessories = @user.accessories
end
private
def update_params
params.require( :user ).permit(
:first_name,
:last_name,
:region_id,
:country,
:profile_image,
:remove_profile_image,
accessory_ids: [:id],
)
end
今問題:
データベースに手動で入力された値が既にある場合にフォームを送信すると、実際には現在保存されているすべての値が削除され、新しい値は追加されません。
Started PATCH "/users/nuggles" for 127.0.0.1 at 2015-02-18 13:31:50 -0500 Processing by UsersController#update as HTML Parameters: { "utf8"=>"✓",···· "authenticity_token"=>"my_token",· "user"=>{ "accessory_ids"=>["5"] },· "button"=>"",· "id"=>"nuggles" } User Load (40.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 4]] User Load (36.4ms) SELECT "users".* FROM "users" WHERE "users"."slug" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["slug", "nuggles"]]· (33.5ms) BEGIN Accessory Load (34.1ms) SELECT "accessories".* FROM "accessories" INNER JOIN "user_accessories" ON "accessories"."id" = "user_accessories"."accessory_id" WHERE "user_accessories"."user_id" = $1 [["user_id", 4]] **SQL (34.1ms) DELETE FROM "user_accessories" WHERE "user_accessories"."user_id" = $1 AND "user_accessories"."accessory_id" IN (1, 2, 3) [["user_id", 4]]** User Exists (37.7ms) SELECT 1 AS one FROM "users" WHERE (LOWER("users"."username") = LOWER('Nuggles') AND "users"."id" != 4) LIMIT 1 (34.2ms) COMMIT Redirected to http://localhost:3000/users/nuggles Completed 302 Found in 304ms (ActiveRecord: 250.0ms)
何も選択されていない状態でフォームを送信すると、次のエラーが表示されます。
param is missing or the value is empty: user private def update_params params.require( :user ).permit( :first_name, :last_name, :region_id,