Ruby 于 Rails 'has_many :through',正在存储数据

Ruby on Rails 'has_many :through', storing data

在我的应用程序中,我有一个 "bookings" table 和一个 "extras" table。

这是一个多对多的关系。因此我创建了一个名为 "additions"

的中间 table

我已经使用 "has_many :through" 建立了 table 之间的关系:

class Booking < ActiveRecord::Base
  has_many :additions
  has_many :extras, :through => :additions


class Extra < ActiveRecord::Base
  has_many :additions
  has_many :extras, :through => :additions

class Addition < ActiveRecord::Base
  belongs_to :booking
  belongs_to :extra

这似乎有效。我手动向一些现有预订添加了一些额外服务(通过添加数字 table),并编写了代码,以便当您单击以显示预订时,它会列出所有相关的额外服务。

现在我需要做到这一点,以便在您进行预订时 - "extras" 保存到中间(添加项)table。

我的预订表单页面上有复选框:

 <%= f.label 'Extras:' %>
    <%= f.collection_check_boxes :extra_ids, Extra.all, :id, :extra_info %>

但很明显,当用户点击保存时,选择就会被丢弃。

我需要一些代码(在控制器中?)将这些 "extras" 保存到 "additions table" ?

任何想法,因为我不知道该怎么做?!

谢谢!


    class BookingsController < ApplicationController
      respond_to :html, :xml, :json

      before_action :find_room
      # before_action :find_extra


      def index
        @bookings = Booking.where("room_id = ? AND end_time >= ?", @room.id, Time.now).order(:start_time)
        respond_with @bookings
      end

      def new
        @booking = Booking.new(room_id: @room.id)
      end

      def create
        @booking =  Booking.new(params[:booking].permit(:room_id, :start_time, :length, :user_id))
        @booking.room = @room
        if @booking.save
          redirect_to room_bookings_path(@room, method: :get)
        else
          render 'new'
        end
      end

      def show
        @booking = Booking.find(params[:id])
      end

      def destroy
        @booking = Booking.find(params[:id]).destroy
        if @booking.destroy
          flash[:notice] = "Booking: #{@booking.start_time.strftime('%e %b %Y %H:%M%p')} to #{@booking.end_time.strftime('%e %b %Y %H:%M%p')} deleted"
          redirect_to room_bookings_path(@room)
        else
          render 'index'
        end
      end

      def edit
        @booking = Booking.find(params[:id])
      end

      def update
        @booking = Booking.find(params[:id])
        # @booking.room = @room

        if @booking.update(params[:booking].permit(:room_id, :start_time, :length, :user_id))
          flash[:notice] = 'Your booking was updated succesfully'

          if request.xhr?
            render json: {status: :success}.to_json
          else
            redirect_to resource_bookings_path(@room)
          end
        else
          render 'edit'
        end
      end

      private

      def save booking
        if @booking.save
            flash[:notice] = 'booking added'
            redirect_to room_booking_path(@room, @booking)
          else
            render 'new'
          end
      end

      def find_room
        if params[:room_id]
          @room = Room.find_by_id(params[:room_id])
        end
      end

      # def find_extra
      #    if params[:extra_id]
      #      @extra = Extra.find_by_id(params[:extra_id])
      #    end
      # end

        # If resource not found redirect to root and flash error.
        def resource_not_found
            yield
        rescue ActiveRecord::RecordNotFound
            redirect_to root_url, :notice => "Booking not found."
        end

      def booking_params
         params.require(:booking).permit(:user_id, :extra_id)
      end

    end

------------------------

class AdditionsController < ApplicationController
  before_action :set_addition, only: [:show, :edit, :update, :destroy]

  # GET /additions
  def index
    @additions = Addition.all
  end

  # GET /additions/1
  def show
  end

  # GET /additions/new
  def new
    @addition = Addition.new
  end

  # GET /additions/1/edit
  def edit
  end

  # POST /additions
  def create
    @addition = Addition.new(addition_params)

    if @addition.save
      redirect_to @addition, notice: 'Addition was successfully created.'
    else
      render :new
    end
  end

  # PATCH/PUT /additions/1
  def update
    if @addition.update(addition_params)
      redirect_to @addition, notice: 'Addition was successfully updated.'
    else
      render :edit
    end
  end

  # DELETE /additions/1
  def destroy
    @addition.destroy
    redirect_to additions_url, notice: 'Addition was successfully destroyed.'
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_addition
      @addition = Addition.find(params[:id])
    end

    # Only allow a trusted parameter "white list" through.
    def addition_params
      params.require(:addition).permit(:booking_id, :extra_id, :extra_name)
    end
end

--------------------------------------

# @author Stacey Rees <https://github.com/staceysmells>
class ExtrasController < ApplicationController
    # @see def resource_not_found
    around_filter :resource_not_found
    before_action :set_extra, only: [:show, :edit, :update, :destroy]

    def index
        @extras = Extra.all
    end

    def show
    end

    def new
        @extra = Extra.new
    end

    def edit
    end

    def create
        @extra = Extra.new(extra_params)

        if @extra.save
            redirect_to @extra, notice: 'Extra was successfully created.'
        else
            render :new
        end
    end

    def update
        if @extra.update(extra_params)
            redirect_to @extra, notice: 'Extra was successfully updated.'
        else
            render :edit
        end
    end

    def destroy
        @extra.destroy
        redirect_to extras_url, notice: 'Extra was successfully destroyed.'
    end

    private
    # Use callbacks to share common setup or constraints between actions.
    def set_extra
        @extra = Extra.find(params[:id])
    end

    # If resource not found redirect to root and flash error.
    def resource_not_found
        yield
    rescue ActiveRecord::RecordNotFound
        redirect_to root_url, :notice => "Room Category not found."
    end

    # Only allow a trusted parameter "white list" through.
    def extra_params
        params.require(:extra).permit(:extraimg, :name, :description, :quantity, :price, :extracat_id)
    end
end

您在这里所做的是使用嵌套表单属性。它有点复杂,但也是人们经常做的事情,所以有一些很好的资源可用。

我建议你看看这个post:http://www.sitepoint.com/complex-rails-forms-with-nested-attributes/

特别是,名为“More Complicated Relationships”的部分有一个使用嵌套属性设置多对多关联的示例,使用 has_many :through

关键部分(评论者已经指出)将是您的预订模型中的 accepts_nested_attributes_for :extras,以及视图中的 f.fields_for :extras 块。您还需要修改 booking_params 方法以允许嵌套值。您可能会 运行 遇到一些严重的参数陷阱,因此您可能需要查看 the documentation.

事实证明,一旦 accepts_nested_attributes_for 被写入,我的代码就快完成了。

我的主要问题是在控制器中设置 booking_params 方法。我通过在 params.permit.

中声明 :extra_ids => [] 使其工作