如何创建事件注册 rails 结构
How to create an event registration rails structure
我有一个我认为是简单的事件注册应用程序。用户注册站点,然后可以 select 一个事件,通过更新用户模型上的一些字段申请参与该事件(此时,只是一个 first_name)。用户可以参加许多活动,但必须为每个活动注册(参与)。一个事件可以通过参与有很多用户。非常感谢任何帮助!
目前有三种型号:
# user.rb
class User < ActiveRecord::Base
has_many :participations
has_many :events, through: :participations
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
# event.rb
class Event < ActiveRecord::Base
has_many :participations
has_many :users, through: :participations
end
# And a join table: participation.rb
class Participation < ActiveRecord::Base
belongs_to :user
belongs_to :event
accepts_nested_attributes_for :user
end
这是我的路线文件:
routes.rb
Rails.application.routes.draw do
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
devise_for :users
root 'events#index'
resources :events do
resources :participations
end
resources :users
end
我认为唯一适用的控制器:
participations_controller.rb
class ParticipationsController < ApplicationController
def index
end
def new
@participation = Participation.new
@user = current_user
@event = Event.find(params[:event_id])
end
def create
@participation = Participation.new(participation_params)
if @participation.save
redirect_to events_path, notice: "You are registered!"
else
render action: 'new'
end
end
private
def participation_params
params.require(:participation).permit(:status, :user_attributes => [:id, :first_name])
end
end
表单应该简单地创建一个基于 event_id 的新参与,设置其状态,并更新 user_attributes。
views/participations/new.html.erb
<%= form_for @participation, url: {action: "create"} do |f| %>
<%= f.label :status %><br />
<%= f.text_field :status %>
<%= f.fields_for :user, current_user do |builder| %>
<fieldset>
<%= builder.label :first_name, "First Name" %><br />
<%= builder.text_field :first_name %><br />
</fieldset>
<% end %>
<%= f.submit "Register" %>
<% end %>
不幸的是,填写表格 returns 出现 404 错误,缺少 participation_id。
Started POST "/events/1/participations" for ::1 at 2015-11-24 21:26:35 -0600
Processing by ParticipationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0vVTyeGwGUheZPbOoMeyUvr2ciJG2OpXwqToc2pYLr2HXDMhogX8llESiG8Z4Cc5Pq5sBmiHi43rvjHka7K3yA==", "participation"=>{"status"=>"done", "user_attributes"=>{"first_name"=>"sone", "id"=>"1"}}, "commit"=>"Register", "event_id"=>"1"}
Completed 404 Not Found in 3ms (ActiveRecord: 0.0ms)
ActiveRecord::RecordNotFound - Couldn't find User with ID=1 for Participation with ID=:
正如 here 所述,发生的情况是,当您将 id 传递给嵌套模型时,accepts_nested_attributes
将查找并尝试更新您正在寻找的模型。
所以此时当前用户与您要创建的参与之间没有这种关联,这就是您收到错误的原因:
Couldn't find User with ID=1 for Participation with ID=:
这意味着没有 ID=1 的用户与您的参与相关联
我的建议:
为什么不为用户添加嵌套属性,为什么不直接将您需要的字段添加到参与模型中呢?
将 first_name
属性添加到您的参与模型,并在您的控制器中执行以下操作:
class ParticipationsController < ApplicationController
def index
end
def new
@participation = Participation.new
@participation.user = current_user
@participation.event = Event.find(params[:event_id])
end
def create
@participation = Participation.new(participation_params)
@participation.user = current_user
@participation.event = Event.find(params[:event_id])
if @participation.save
redirect_to events_path, notice: "You are registered!"
else
render action: 'new'
end
end
private
def participation_params
params.require(:participation).permit(:status, :first_name)
end
end
然后在您的表单中,您可以进行正常的 first_name 输入:
<fieldset>
<%= f.label :first_name, "First Name" %><br />
<%= f.text_field :first_name %><br />
</fieldset>
尝试一下并告诉我,顺便说一下,不要忘记从参与模型中删除 accepts_nested_attributes
,并确保正确设置迁移以匹配您拥有的关联。希望对你有所帮助。
更新
如果您不想在参与中保留用户信息,那么您只需将属性访问器添加到您的参与模型中,然后将信息存储在您的 current_user
中的 create
操作中:
#app/models/participation.rb
class Participation < ActiveRecord::Base
belongs_to :user
belongs_to :event
attr_accessor :first_name, :whatever_other_attribute # You can add as many attributes you need.
end
然后只需在 create
操作中更新 current_user
的信息:
#app/controllers/participations_controller
def create
@participation = Participation.new(participation_params)
@participation.user = current_user
@participation.event = Event.find(params[:event_id])
current_user.update_attributes first_name: @participation.first_name
if @participation.save
redirect_to events_path, notice: "You are registered!"
else
render action: 'new'
end
end
通过这种方式,您可以将信息存储在 current_user
而不是参与中,而且通过这种方式,您可以轻松自定义您将在参与表单中询问的不同信息。
感谢@ssoulless 指出我最终的解决方案。
最终我能够更新控制器操作以关联用户,然后使用 participation_params 更新参与[:user]。
# participations_controller.rb
...
def create
@participation = Participation.new(status: participation_params[:status])
@participation.mission_id = params[:mission_id]
current_user.update_attributes(participation_params[:user_attributes])
@participation.user = current_user
if @participation.save
redirect_to missions_path, notice: "You are registered!"
else
render action: 'new'
end
end
private
def participation_params
params.require(:participation)
.permit(:id, :status, user_attributes: [:id, :first_name])
end
我更喜欢这种方法,因为它在私有方法中隐藏了用户属性。此外,对于任何可能有帮助的人,在您的模型中使用 accepts_nested_attributes_for
时,您需要将其添加到 strong_params #permit 参数(不要忘记 ID!)。
我有一个我认为是简单的事件注册应用程序。用户注册站点,然后可以 select 一个事件,通过更新用户模型上的一些字段申请参与该事件(此时,只是一个 first_name)。用户可以参加许多活动,但必须为每个活动注册(参与)。一个事件可以通过参与有很多用户。非常感谢任何帮助!
目前有三种型号:
# user.rb
class User < ActiveRecord::Base
has_many :participations
has_many :events, through: :participations
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
# event.rb
class Event < ActiveRecord::Base
has_many :participations
has_many :users, through: :participations
end
# And a join table: participation.rb
class Participation < ActiveRecord::Base
belongs_to :user
belongs_to :event
accepts_nested_attributes_for :user
end
这是我的路线文件: routes.rb
Rails.application.routes.draw do
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
devise_for :users
root 'events#index'
resources :events do
resources :participations
end
resources :users
end
我认为唯一适用的控制器: participations_controller.rb
class ParticipationsController < ApplicationController
def index
end
def new
@participation = Participation.new
@user = current_user
@event = Event.find(params[:event_id])
end
def create
@participation = Participation.new(participation_params)
if @participation.save
redirect_to events_path, notice: "You are registered!"
else
render action: 'new'
end
end
private
def participation_params
params.require(:participation).permit(:status, :user_attributes => [:id, :first_name])
end
end
表单应该简单地创建一个基于 event_id 的新参与,设置其状态,并更新 user_attributes。 views/participations/new.html.erb
<%= form_for @participation, url: {action: "create"} do |f| %>
<%= f.label :status %><br />
<%= f.text_field :status %>
<%= f.fields_for :user, current_user do |builder| %>
<fieldset>
<%= builder.label :first_name, "First Name" %><br />
<%= builder.text_field :first_name %><br />
</fieldset>
<% end %>
<%= f.submit "Register" %>
<% end %>
不幸的是,填写表格 returns 出现 404 错误,缺少 participation_id。
Started POST "/events/1/participations" for ::1 at 2015-11-24 21:26:35 -0600
Processing by ParticipationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0vVTyeGwGUheZPbOoMeyUvr2ciJG2OpXwqToc2pYLr2HXDMhogX8llESiG8Z4Cc5Pq5sBmiHi43rvjHka7K3yA==", "participation"=>{"status"=>"done", "user_attributes"=>{"first_name"=>"sone", "id"=>"1"}}, "commit"=>"Register", "event_id"=>"1"}
Completed 404 Not Found in 3ms (ActiveRecord: 0.0ms)
ActiveRecord::RecordNotFound - Couldn't find User with ID=1 for Participation with ID=:
正如 here 所述,发生的情况是,当您将 id 传递给嵌套模型时,accepts_nested_attributes
将查找并尝试更新您正在寻找的模型。
所以此时当前用户与您要创建的参与之间没有这种关联,这就是您收到错误的原因:
Couldn't find User with ID=1 for Participation with ID=:
这意味着没有 ID=1 的用户与您的参与相关联
我的建议:
为什么不为用户添加嵌套属性,为什么不直接将您需要的字段添加到参与模型中呢?
将 first_name
属性添加到您的参与模型,并在您的控制器中执行以下操作:
class ParticipationsController < ApplicationController
def index
end
def new
@participation = Participation.new
@participation.user = current_user
@participation.event = Event.find(params[:event_id])
end
def create
@participation = Participation.new(participation_params)
@participation.user = current_user
@participation.event = Event.find(params[:event_id])
if @participation.save
redirect_to events_path, notice: "You are registered!"
else
render action: 'new'
end
end
private
def participation_params
params.require(:participation).permit(:status, :first_name)
end
end
然后在您的表单中,您可以进行正常的 first_name 输入:
<fieldset>
<%= f.label :first_name, "First Name" %><br />
<%= f.text_field :first_name %><br />
</fieldset>
尝试一下并告诉我,顺便说一下,不要忘记从参与模型中删除 accepts_nested_attributes
,并确保正确设置迁移以匹配您拥有的关联。希望对你有所帮助。
更新
如果您不想在参与中保留用户信息,那么您只需将属性访问器添加到您的参与模型中,然后将信息存储在您的 current_user
中的 create
操作中:
#app/models/participation.rb
class Participation < ActiveRecord::Base
belongs_to :user
belongs_to :event
attr_accessor :first_name, :whatever_other_attribute # You can add as many attributes you need.
end
然后只需在 create
操作中更新 current_user
的信息:
#app/controllers/participations_controller
def create
@participation = Participation.new(participation_params)
@participation.user = current_user
@participation.event = Event.find(params[:event_id])
current_user.update_attributes first_name: @participation.first_name
if @participation.save
redirect_to events_path, notice: "You are registered!"
else
render action: 'new'
end
end
通过这种方式,您可以将信息存储在 current_user
而不是参与中,而且通过这种方式,您可以轻松自定义您将在参与表单中询问的不同信息。
感谢@ssoulless 指出我最终的解决方案。
最终我能够更新控制器操作以关联用户,然后使用 participation_params 更新参与[:user]。
# participations_controller.rb
...
def create
@participation = Participation.new(status: participation_params[:status])
@participation.mission_id = params[:mission_id]
current_user.update_attributes(participation_params[:user_attributes])
@participation.user = current_user
if @participation.save
redirect_to missions_path, notice: "You are registered!"
else
render action: 'new'
end
end
private
def participation_params
params.require(:participation)
.permit(:id, :status, user_attributes: [:id, :first_name])
end
我更喜欢这种方法,因为它在私有方法中隐藏了用户属性。此外,对于任何可能有帮助的人,在您的模型中使用 accepts_nested_attributes_for
时,您需要将其添加到 strong_params #permit 参数(不要忘记 ID!)。