【问题标题】:Submitting multiple table entries from a single form submission in rails从 rails 中的单个表单提交提交多个表条目
【发布时间】:2022-11-22 13:01:33
【问题描述】:

我正在尝试为我的钓鱼俱乐部会议制作一张出席表,其中显示所有活跃成员并允许您在他们的名字旁边放置一个复选框,以记录他们是否参加了特定锦标赛的会议。我创建了一个“会议”脚手架,并在 _form 中列出了所有活跃成员,并允许用户勾选该成员是否参加了所选锦标赛的会议。但是,我在将哈希数组传递给我的 meetings_controller 时遇到了问题,而且我很困惑。

我读了很多文章,但我的设计基于这篇文章:Submit array of hashes with rails

这篇文章没有显示 create 方法中的内容,所以我有这个......

会议控制器:

def create
    # puts " OUTPUT TEXT: #{params} " 
    
    @meeting = params[:meetings][:meetings]
    
    @meeting.each do |m|

    #If there is no attendance key, its nil. Make it false
    # if !m[:meeting].has_key?("attendance")
    #     m[:meeting].attendance = false
    # end
     
      puts "OUTPUT TEXT: #{m[:meeting]}" # OUTPUT TEXT: {"member_id"=>"1", "tournament_id"=>"2", "attendance"=>"1"}
     
      @meeting = Meeting.new(member_id: m[:meeting][:member_id], tournament_id: m[:meeting][:tournament_id], attendance: m[:meeting][:attendance])
     
   end
    respond_to do |format|
      if @meeting.save
        format.html { redirect_to @meeting, notice: "Meeting was successfully created." }
        format.json { render :show, status: :created, location: @meeting }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @meeting.errors, status: :unprocessable_entity }
      end
    end
  end

_form 输入:(基于上面链接的文章)

<% Member.where(active: true).each do |member| %>
   
   <tr>
    <td> <%= member.full_name %> </td>
    
    <input multiple="multiple" value=<%=member.id %> type="hidden" name="meetings[meetings][]meeting[member_id]" />


    <input multiple="multiple" value=<%=@tournament.id %> type="hidden" name="meetings[meetings][]meeting[tournament_id]" />
    

    <td><input type="checkbox" value="1" name="meetings[meetings][]meeting[attendance]" /></td>
  </tr>
 <% end %> 

当我点击提交表格时,它只是将我带到显示页面,其中只有这个显示在空白页面上......

{"controller"=>"meetings", "action"=>"show", "id"=>"18"}

即使我在 show 方法中有重定向行

def show
    redirect_to meetings_path
end

我花了很多时间阅读,并进行反复试验以使其发挥作用。希望stackoverflow大神们帮忙。

【问题讨论】:

    标签: ruby-on-rails forms hash-of-hashes


    【解决方案1】:

    在控制器中,当您循环通过会议参数时,Meeting 不会保存到数据库并且 @meeting 变量会被覆盖,直到数组中的最后一项...

    @meeting.each do |m|     
      @meeting = Meeting.new(member_id: m[:meeting][:member_id], tournament_id: m[:meeting][:tournament_id], attendance: m[:meeting][:attendance])
    end
    

    ……这就是被拯救的人。

    if @meeting.save
    

    也不确定您的 show 操作发生了什么,保存后不要重定向到它。

    在 Rails 表单中使用数组有点不确定。但它就在这里。

    控制器:

    # params - submitted params from the form
    #          { "authenticity_token"=>"[FILTERED]", 
    #             "meetings"=>[
    #               { "member_id"=>"1", "tournament_id"=>"1", attendance"=>"1" },
    #               ...
    #              ],
    #            "commit"=>"Save"
    #          }
    
    # POST /meetings
    def create
      @meetings = meetings_params.map do |param|
        Meeting.create_with(attendance: param[:attendance])
          .find_or_create_by(member_id: param[:member_id], tournament_id: param[:tournament_id])
      end
      respond_to do |format|
        if @meetings.detect{|m| m.id == nil }  # id=nil if any meetings didn't save
          # FIXME: @tournament not initialized here
          format.html { render :new, status: :unprocessable_entity }
        else
          format.html { redirect_to meetings_url, notice: "Meetings were created." }
        end
      end
    end
    
    # Returns array 
    # [{member_id: 1, tournament_id: 1, attendance: 1}, ...]
    def meetings_params
      params.permit(meetings: [:member_id, :tournament_id, :attendance]).require(:meetings)
    end
    

    形式:

    <%= form_with url: "/meetings" do |f| %>
      <% Member.where(active: true).each do |member| %>
        <%# TODO: if meeting doesn't save, there is no error to show %>
        <%= text_field_tag "meetings[][member_id]",     member.id %>
        <%= text_field_tag "meetings[][tournament_id]", @tournament.id %>
        <%= check_box_tag  "meetings[][attendance]",    Meeting.find_by(member: member, tournament: @tournament)&.attendance %>
      <% end %>
      <%= f.submit %>
    <% end %>
    

    或者使用 fields_for 助手:

    <%= form_with url: "/meetings" do |f| %>
      <% Member.where(active: true).each do |member| %>
        <%#                            this nil does the [] thing %>
        <%#                                     |                 %>
        <%= fields_for "meetings", nil, index: nil do |ff| %>
          <%= ff.number_field "member_id",     value: member.id %>
          <%= ff.hidden_field "tournament_id", value: @tournament.id %>
          <%= ff.check_box    "attendance",    value: Meeting.find_by(member: member, tournament: @tournament)&.attendance %>
        <% end %>
      <% end %>
      <%= f.submit %>
    <% end %>
    

    更新

    可以这么说,以上所有内容确实是违反轨道的。这是我想出的让它超级简单的方法:

    我们需要一个Attendance表来跟踪每个Meeting的每个成员的出席情况:

    # db/migrate/20221122034503_create_attendances.rb 
    class CreateAttendances < ActiveRecord::Migration[7.0]
      def change
        create_table :attendances do |t|
          t.boolean :attended
          t.references :meeting, null: false, foreign_key: true
          t.references :member,  null: false, foreign_key: true
        end
      end
    end
    
    # app/models/attendance.rb 
    class Attendance < ApplicationRecord
      belongs_to :meeting
      belongs_to :member
    end
    
    # app/models/meeting.rb
    class Meeting < ApplicationRecord
      has_many :attendances
      # NOTE: let rails take care of nested attendances from the form
      accepts_nested_attributes_for :attendances
    end
    

    MeetingsController 是默认脚手架:

    bin/rails g scaffold_controller meeting
    

    只需更新new 操作:

    # app/controllers/meetings_controller.rb
    def new
      @meeting = Meeting.new
      # NOTE: build a list of attendances for the form to render
      Member.where(active: true).each do |member|
        @meeting.attendances.build(member: member)
      end
    end
    

    表格现在超级简单:

    <!-- app/views/meetings/_form.html.erb -->
    <%= form_with model: @meeting do |f| %>
      <%= f.fields_for :attendances do |ff| %>
        <%= ff.number_field :member_id %>
        <%= ff.check_box :attended %>
      <% end %>
      <%= f.submit %>
    <% end %>
    

    createupdate 自己工作。

    【讨论】:

    • 太感谢了!我离开了一会儿,很高兴回到答案。这将帮助我继续改进我的网站,并且我学到了一些新东西。我想投票,但我仍然需要更多的声誉。
    • 所以我现在可以使用您的代码......但是我正在努力使用编辑功能。我几乎只需要 1 个编辑按钮来编辑该锦标赛的成员出席人数,但是......按照我认为合理的方式进行操作会给我一个我不理解的 rails 代码深处的错误。
    • 我需要在编辑或更新中向控制器添加什么才能使更新功能正常工作?
    • @railsnoob 好的,我已经更新了答案,希望这会为您指明正确的方向。
    猜你喜欢
    • 1970-01-01
    • 2016-04-06
    • 1970-01-01
    • 1970-01-01
    • 2014-10-12
    • 1970-01-01
    • 2014-10-30
    • 2011-03-20
    • 1970-01-01
    相关资源
    最近更新 更多