简体   繁体   中英

Shopping cart with multiply models

We built (based on the book Agile webdev Rails4) a shopping/inquiry cart.

Visitor can add line_items (houses)to the cart and and then checkout. When the visitor checks out a lead is created.

My models:

class House < ActiveRecord::Base
has_many :line_items
end

class LineItem < ActiveRecord::Base
  belongs_to :lead


  belongs_to :house

  belongs_to :cart

end



 class Lead < ActiveRecord::Base
    has_many :line_items, dependent: :destroy



  def add_line_items_from_cart(cart)
    cart.line_items.each do |item|
      line_items << item
    end
  end

end

class Cart < ActiveRecord::Base
  has_many :line_items, dependent: :destroy
  accepts_nested_attributes_for :line_items


end

A module for creating the session cart

module CurrentCart
  extend ActiveSupport::Concern

  private

    def set_cart 
      @cart = Cart.find(session[:cart_id])
    rescue ActiveRecord::RecordNotFound
      @cart = Cart.create
      session[:cart_id] = @cart.id 
    end
end

Carts_controller

class CartsController < ApplicationController
  before_action :set_cart, only: [:show, :edit, :update, :destroy]

    def create
        @cart = Cart.new(cart_params)

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

Line_item Controller

class LineItemsController < ApplicationController
  skip_before_action :authorize, only: :create
  include CurrentCart
  before_action :set_cart, only: [:create]
  before_action :set_line_item, only: [:show, :edit, :update, :destroy]

def create

    house = House.find(params[:house_id])
    @line_item = @cart.line_items.build(house_id: house.id)

    respond_to do |format|
      if @line_item.save
        format.html { redirect_to @line_item.cart,
          notice: 'Vakantiehuis toegevoegd in lijst.' }
        format.json { render action: 'show',
          status: :created, location: @line_item }
      else
        format.html { render action: 'new' }
        format.json { render json: @line_item.errors,
          status: :unprocessable_entity }
      end
    end
  end

leads_controller

class LeadsController < ApplicationController
  include CurrentCart
  before_action :set_cart, only: [:new, :create]

 def create
    @lead = Lead.new(lead_params)
    @lead.add_line_items_from_cart(@cart)

    respond_to do |format|
      if @lead.save

        format.html { redirect_to @lead, notice: 
          'Thank you for your order.' }
        format.json { render action: 'show', status: :created,
          location: @order }

      else
        format.html { render action: 'new' }
        format.json { render json: @lead.errors,
          status: :unprocessable_entity }
      end

    end

  end
end

We want to add a new model (apartments to the shopping cart). So i added apartment_id in the line_items table and changed the models

class Apartment < ActiveRecord::Base
    has_many :line_items
    end


class LineItem < ActiveRecord::Base
      belongs_to :lead


      belongs_to :house
      belongs_to :apartment


      belongs_to :cart

    end

But i don't now how i must change the create method in the LineItems_controller so we can add houses and apartments to the cart?

THanks remco

You'll want to change your line_items model to have a polymorphic association :

在此处输入图片说明

Polymorphic associations are simply when you have the ability to associate different objects in the same model. This would not be correct if your apartments were child-objects of the House model, but as they are independent, you'll be able to associate them polymorphically

Here's how I'd do it:

#app/models/line_item.rb
class LineItem < ActiveRecord::Base
   belongs_to :item, polymorphic: true
end

#app/models/house.rb
class House < ActiveRecord::Base
   has_many :line_items, as: :items
end

#app/models/apartment.rb
class Apartment < ActiveRecord::Base
   has_many :line_items, as: :items
end

This will give you the ability to do the following:

#app/controllers/line_items.controller.rb
class LineItemsController < ApplicationController
   before_action :create_object

   def create
      @line_item = @cart.line_items.build item: @object
      @line_items.save
   end

   private

   def create_object
      id = params[:house_id] || params[:apartment_id]

      model = "House" if params[:house_id]
      model = "Apartment" if params[:apartment_id]
      model. constantize

      @object = model.find id
   end
end

This should reference the correct model for you the ability to save either an apartment or a house to your LineItem model

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM