【问题标题】:Rails 4 - How to insert an additional row when you submit a form?Rails 4 - 提交表单时如何插入额外的行?
【发布时间】:2018-03-10 17:31:40
【问题描述】:

我正在使用 Ruby on Rails 构建一个简单的应用程序。我的数据库中有三个表:userseventsinvites

任何用户都可以通过表单创建邀请,在表单中他/她选择他/她想要邀请的用户,以及他/她想要邀请的事件想邀请那个人。

现在,我希望每次有人创建邀请时,他/她也会邀请另一个名为“Intruder”的用户。

因此,每次提交邀请表单时,都应在数据库中插入两行:

  • 首先是用户选择的数据
  • 第二个地方 user_id 与“入侵者”的 id 匹配,而 event_id 与第一行相同。

这是我的邀请控制器:

  def new
    @invite = Invite.new
    @users = User.where.not(:id => current_user).order(full_name: :ASC)
    @user = User.new
    @events = Event.where(:user_id => current_user).order(startsAt: :ASC)
    @event = Event.new
  end

  def create
    @users = User.where.not(:id => current_user).order(full_name: :ASC)
    @user = User.new
    @events = Event.where(:user_id => current_user).order(startsAt: :ASC)
    @event = Event.new
    @invite = Invite.new(invite_params)

    respond_to do |format|
      if @invite.save
        format.html { redirect_to events_path, notice: 'Invite was successfully created.' }
        format.json { render :show, status: :created, location: @invite }
      else
        format.html { render :new }
        format.json { render json: @invite.errors, status: :unprocessable_entity }
      end
    end
  end

  def invite_params
    params.require(:invite).permit(:attending, :user_id, :event_id)
  end

这是我创建新邀请的表单:

<%= form_for(@invite) do |f| %>
  <% if @invite.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@invite.errors.count, "error") %> prohibited this invite from being saved:</h2>

      <ul>
      <% @invite.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :user_id, 'Name' %>
    <%= f.select :user_id, options_for_select(@users.collect { | user | [user.full_name, user.id] }, @user.id), {}, class: 'inv-select' %>
  </div>
  <div class="field">
    <%= f.label :event_id %>
    <%= f.select :event_id, options_for_select(@events.collect { | event | [event.title, event.id] }, @event.id), {}, class: 'inv-select' %>
  </div>
  <div class="actions">
    <%= f.submit 'Invite' %>
  </div>
<% end %>

【问题讨论】:

    标签: ruby-on-rails


    【解决方案1】:

    如果我正确理解了您的问题,则无需将 Intruder 部分添加到您的视图中,因为它只是一个后端实现细节。

    因此,您可以将 Intruder 插入部分提取到一个方法中,并在为其他用户插入新邀请后立即调用它:

    def create
      @users = User.where.not(:id => current_user).order(full_name: :ASC)
      @user = User.new
      @events = Event.where(:user_id => current_user).order(startsAt: :ASC)
      @event = Event.new
      @invite = Invite.new(invite_params)
    
      respond_to do |format|
        if @invite.save && invite_intruder          
          format.html { redirect_to events_path, notice: 'Invite was successfully created.' }
          format.json { render :show, status: :created, location: @invite }
        else
          format.html { render :new }
          format.json { render json: @invite.errors, status: :unprocessable_entity }
        end
      end
    end
    
    protected
    
    def invite_intruder
      intruder = User.find_by(full_name: "Intruder")
      Invite.new(event_id: invite_params[:event_id], user_id: intruder.id).save
    end
    

    您可能希望添加一些自定义错误处理以防 Intruder 的邀请失败,但不清楚您是否希望第二次邀请对用户透明或隐藏。 p>

    【讨论】:

    • 你正确地理解了我。我希望第二次邀请对用户透明,但我知道如何处理。感谢您的帮助。
    【解决方案2】:

    你可以给邀请模型添加一个辅助属性,来控制入侵者:

    attr_accesor :intruder_id
    

    您可以在表单中添加入侵者:

    <div class="field">
      <%= f.label :intruder_id, 'Intruder' %>
      <%= f.select :intruder_id, options_for_select(@users.collect { | user | [user.full_name, user.id] }), {}, class: 'inv-select' %>
    </div>
    

    将 intruder_id 添加到参数中

    def invite_params
      params.require(:invite).permit(:attending, :user_id, :intruder_id, :event_id)
    end
    

    你不需要新的用户和事件

    def new
      @invite = Invite.new
      @users = User.where.not(:id => current_user).order(full_name: :ASC)
      @events = Event.where(:user_id => current_user.id).order(startsAt: :ASC)
    end
    

    创建两个邀请:

    def create
      @users = User.where.not(:id => current_user).order(full_name: :ASC)
      @events = Event.where(:user_id => current_user).order(startsAt: :ASC)
      @invite = Invite.new(invite_params)
      @intruder_invite Invite.new(invite_params)
      @intruder_invite.user_id = invite_params[:intruder_id] # Change the invitee
    
      respond_to do |format|
        if @invite.save
          if @intruder_invite.save
            format.html { redirect_to events_path, notice: 'Main and intruder invites were successfully created.' }
            format.json { render :show, status: :created, location: @invite }
          else
            format.html { redirect_to events_path, notice: 'Main invite was created, but an error prevented the intruder invite to be created.' }
            format.json { render :show, status: :created, location: @invite }
          end
        else
          format.html { render :new }
          format.json { render json: @invite.errors, status: :unprocessable_entity }
        end
      end
    end
    

    【讨论】:

      【解决方案3】:

      这将是 rails 中 callbacks mechanism 的函数,可能是 before_create 回调,因为它不需要额外的保存。

      class Invite < ApplicationRecord
        before_create :add_intruder
      
        protected
      
        def add_intruder
          self.users << User.find_by full_name: "Intruder"
        end
      
      end
      

      虽然 TBH 更好的方法是通过触发器在 SQL 中处理这个问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-16
        • 2012-09-05
        • 1970-01-01
        • 2018-02-08
        • 1970-01-01
        • 1970-01-01
        • 2017-10-20
        • 1970-01-01
        相关资源
        最近更新 更多