欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Ruby On Rails的第一个应用(六)--创建购物车

程序员文章站 2022-03-02 23:53:44
...

IV 任务D:创建购物车 

 

任务列表:

·会话和会话管理

·添加模型间的关系

·创建一个按钮,可添加产品到购物车中

 

一、迭代D1:寻找购物车

应用程序需要跟踪所有由买家添加到购物车中的商品。所以需要把购物车放到数据库中,并在会话中存储该购物车的唯一标识符cart.id。每当请求出现时,可以从会话中找到该购物车的标识,并用该标识在数据库中查找购物车。

1.创建一个购物车:

Administrator@JARRY /e/works/ruby/depot (master)
$ rails generate scaffold cart
        SECURITY WARNING: No secret option provided to Rack::Session::Cookie.
        This poses a security threat. It is strongly recommended that you
        provide a secret to prevent exploits that may be possible from crafted
        cookies. This will not be supported in future versions of Rack, and
        future versions will even invalidate your existing user cookies.
 
        Called from: d:/dev/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/actionpack-3.2.1/lib/action_dispatch/middleware/
session/abstract_store.rb:28:in `initialize'.
 
      invoke  active_record
      create    db/migrate/20130319021136_create_carts.rb
      create    app/models/cart.rb
      invoke    test_unit
      create      test/unit/cart_test.rb
      create      test/fixtures/carts.yml
       route  resources :carts
      invoke  scaffold_controller
      create    app/controllers/carts_controller.rb
      invoke    erb
      create      app/views/carts
      create      app/views/carts/index.html.erb
      create      app/views/carts/edit.html.erb
      create      app/views/carts/show.html.erb
      create      app/views/carts/new.html.erb
      create      app/views/carts/_form.html.erb
      invoke    test_unit
      create      test/functional/carts_controller_test.rb
      invoke    helper
      create      app/helpers/carts_helper.rb
      invoke      test_unit
      create        test/unit/helpers/carts_helper_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/carts.js.coffee
      invoke    scss
      create      app/assets/stylesheets/carts.css.scss
      invoke  scss
   identical    app/assets/stylesheets/scaffolds.css.scss

    

2.

Administrator@JARRY /e/works/ruby/depot (master)
$ rake db:migrate
==  CreateCarts: migrating ====================================================
-- create_table(:carts)
   -> 0.0781s
==  CreateCarts: migrated (0.0781s) ===========================================

  

3.

rails会话看上去像控制器的一个散列,所以将这个购物车id放在会话中,其可以使用符号:card_id建立索引。

/app/controllers/application_controller.rb

 

class ApplicationController < ActionController::Base
  protect_from_forgery
  
  private
  
    def current_cart
      Cart.find(session[:cart_id])
    rescue ActiveRecord::RecordNotFound
      cart = Cart.create
      session[:cart_id] = cart.id
      cart
    end
    
end

 

二、迭代D2:将产品放到购 物车中

购物车中包含了一些选购的货品。创建rails模型并应用迁移来创建相应的数据库表

 1.

Administrator@JARRY /e/works/ruby/depot (master) 
$ rails generate scaffold line_item product_id:integer cart_id:integer
        SECURITY WARNING: No secret option provided to Rack::Session::Cookie.
        This poses a security threat. It is strongly recommended that you
        provide a secret to prevent exploits that may be possible from crafted
        cookies. This will not be supported in future versions of Rack, and
        future versions will even invalidate your existing user cookies.
 
        Called from: d:/dev/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/actionpack-3.2.1/lib/action_dispatch/middle
ware/session/abstract_store.rb:28:in `initialize'.
 
      invoke  active_record
      create    db/migrate/20130319022813_create_line_items.rb
      create    app/models/line_item.rb
      invoke    test_unit
      create      test/unit/line_item_test.rb
      create      test/fixtures/line_items.yml
       route  resources :line_items
      invoke  scaffold_controller
      create    app/controllers/line_items_controller.rb
      invoke    erb
      create      app/views/line_items
      create      app/views/line_items/index.html.erb
      create      app/views/line_items/edit.html.erb
      create      app/views/line_items/show.html.erb
      create      app/views/line_items/new.html.erb
      create      app/views/line_items/_form.html.erb
      invoke    test_unit
      create      test/functional/line_items_controller_test.rb
      invoke    helper
      create      app/helpers/line_items_helper.rb
      invoke      test_unit
      create        test/unit/helpers/line_items_helper_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/line_items.js.coffee
      invoke    scss
      create      app/assets/stylesheets/line_items.css.scss
      invoke  scss
   identical    app/assets/stylesheets/scaffolds.css.scss
 

 

2.

Administrator@JARRY /e/works/ruby/depot (master)
$ rake db:migrate
==  CreateLineItems: migrating ================================================
-- create_table(:line_items)
   -> 0.0781s
==  CreateLineItems: migrated (0.0781s) =======================================

  

3.表建完了,现在在数据库中有地方来存放在线商品、购物车和产品之间的关系了。然而,rails应用程序并不是把这些关系放在数据库中。我们需要在模型文件中添加一些声明来说明它们之间的关系。

在/app/models下修改cart.rb添加has_many的调用:

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

  

4.从相反的方向来定义连接,人在线商品到carts和products表。为了实现这个,要在文件line_item.rb中使用两次belongs_to声明:

/app/models/line_item.rb

class LineItem < ActiveRecord::Base
  belongs_to :product
  belongs_to :cart
end

 

belongs_to声明放在哪里?简单地说,如果一个数据库表有外键,那么在相应的模型中每个外键都要有个belongs_to声明

 

5.出于完整性的考虑,应该在模型Product中也添加一个has_many指令。毕竟,如果我们有许多个购物车的话,每个产品也可以有多个在线商品引用它。这次我们用验证代码来避免删除那些正在被在线商品引用的产品。

/app/models/product.rb

class Product < ActiveRecord::Base
  default_scope order: 'title'
  has_many :line_items
  before_destroy :ensure_not_referenced_by_any_line_item
  
# ... 之前的验证代码
 
private
 
#ensure that there are no line items referencing this product
def ensure_not_refrenced_by_any_line_item
  if line_items.empty?
    return true
  else 
    errors.add(:base, 'Line Items present')
    return false
  end
end
 
end

  

三、迭代D3:添加一个按钮

模型间的关系处理完毕,该给每个产品添加一个Add to Cart按钮了。

我们不必创建新的控制器,甚至不必创建一个新的行为。脚手架生成器提供了:index、show、new、edit、create、update和destroy。我们正好可用的行为create。(行为new可能听上去也差不多,但是这个行为通常是要获得一个表单,可在其中输入某些信息,然后再由行为create继续下去。)

1.添加链接前我们使用了link_to,但链接默认使用http get方法。这里我们想用post,所以这次我们需要添加一个按钮,要用button_to方法。

可以通过指定url来将按钮和在线商品联系起来,但是rails可简单地将_path追加到控制器的名称后,用rails来处理,这里可以用line_items_path。

现在问题是哪个产品要添加到购物车中呢?这就需要把对应的产品id也传给这个方法。

/app/views/store/index.html.erb

<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>
 
<h1>Your Pragmatic Catalog</h1>
 
<% @products.each do |product| %>
<div class="entry">
<%= image_tag(product.image_url) %>
<h3><%= product.title %></h3>
<%= sanitize(product.description) %>
<div class="price_line">
<span class="price"><%= number_to_currency(product.price, unit: "¥") %></span>
<%= button_to 'Add to Cart', line_items_path(product_id: product) %>
</div>
</div>
<% end %>
 

 

2.

/app/assets/stylesheets/store.css.scss

// Place all the styles related to the Store controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
 
/* START_HIGHLIGHT */
.store {
  h1 {
    margin: 0;
    padding-bottom: 0.5em;
    font:  150% sans-serif;
    color: #226;
    border-bottom: 3px dotted #77d;
  }
 
  /* An entry in the store catalog */
  .entry {
    overflow: auto;
    margin-top: 1em;
    border-bottom: 1px dotted #77d;
    min-height: 100px;
 
    img {
      width: 80px;
      margin-right: 5px;
      margin-bottom: 5px;
      position: absolute;
    }
 
    h3 {
      font-size: 120%;
      font-family: sans-serif;
      margin-left: 100px;
      margin-top: 0;
      margin-bottom: 2px;
      color: #227;
    }
 
//#START:inline
    p, div.price_line {
      margin-left: 100px;
      margin-top: 0.5em; 
      margin-bottom: 0.8em; 
 
      /* START_HIGHLIGHT */
      form, div {
        display: inline;
      }
      /* END_HIGHLIGHT */
    }
//#END:inline
 
    .price {
      color: #44a;
      font-weight: bold;
      margin-right: 3em;
    }
  }
}
/* END_HIGHLIGHT */

 

3.添加按钮后效果

Ruby On Rails的第一个应用(六)--创建购物车
            
    
    博客分类: ruby on rails railsruby on railsRuby On Rails的第一个应用depot

 

4.现在我们来修改LineItemsContorller以找到购物车中的内容。我们需要做的只是在/app/controllers/line_items_controller.rb的create方法中修改几行代码:

 

 def create
    @cart = current_cart
    product = Product.find(params[:product_id])
    @line_item = @cart.line_items.build(product: product)
 
    respond_to do |format|
      if @line_item.save
        format.html { redirect_to @line_item.cart, notice: 'Line item was successfully created.' }
        format.json { render json: @line_item, status: :created, location: @line_item }
      else
        format.html { render action: "new" }
        format.json { render json: @line_item.errors, status: :unprocessable_entity }
      end
    end
  end

 

 

5.每当修改控制器功能时,我们知道需要更新相应的功能测试。在调用create方法时需要传递产品id给该方法,并将重定向的网址修改为我们想要的。通过修改/test/functional/line_items_controller_test.rb实现:

 test "should create line_item" do
    assert_difference('LineItem.count') do
      post :create, product_id: products(:ruby).id
    end
 
    assert_redirected_to cart_path(assigns(:line_item).cart)
  end

  

6.rake test:functionals

 

7.显示购物车,创建简单的模板,/app/views/carts/show.html.erb:

<h2>Your Pragmatic Cart<h2>
<ul>
<% @cart.line_items.each do |item| %>
<li><%= item.product.title %></li>
<% end %>
</ul>

 

8.点击add to cart添加到购物车后

Ruby On Rails的第一个应用(六)--创建购物车
            
    
    博客分类: ruby on rails railsruby on railsRuby On Rails的第一个应用depot