如何创建事件注册 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!)。