Skip to content

romalopes/depot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

$ rails new depot

$ rails generate scaffold Product title:string description:text image_url:string price:decimal

Creates depot_a/db/migrate/20110211000001_create_products.rb class CreateProducts < ActiveRecord::Migration def self.up create_table :products do |t| t.string :title t.text :description t.string :image_url t.decimal :price, :precision => 8, :scale => 2 t.timestamps end end end

$ rake db:migrate

$ rails server

depot_b/db/seeds.rb Product.delete_all # . . . Product.create(:title => ‘Programming Ruby 1.9’, :description => %{<p> Ruby is the fastest growing and most exciting dynamic language out there. If you need to get working programs delivered fast, you should add Ruby to your toolbox. </p>}, :image_url => ‘/images/ruby.jpg’, :price =

$ rake db:seed

Validation In app/models/product.rb: class Product < ActiveRecord::Base validates :title, :description, :image_url, :presence => true validates :title, :uniqueness => true validates :price, :numericality => {:greater_than_or_equal_to => 0.01} validates :image_url, :format => { :with => %r{\.(gif|jpg|png)$}i, :message => ‘must be a URL for GIF, JPG or PNG image.’ } end

$ rake test

create the test. In this case is unit test

depot_c/test/functional/products_controller_test.rb depot_c/test/unit/product_test.rb

Fixtures(YAML or yml) Has data to test The name of the file must be the same as the table in database Ex: test/fixtures/products.yml It has the entry of each row to be inserted in database To load the data class ProductTest < ActiveSupport::TestCase fixtures :products

Catalog Display Creating the Catalog Listing Create the controller store

rails generate controller store index create app/controllers/store_controller.rb route get “store/index” invoke erb create app/views/store create app/views/store/index.html.erb invoke test_unit create test/controllers/store_controller_test.rb invoke helper create app/helpers/store_helper.rb invoke test_unit create test/helpers/store_helper_test.rb invoke assets invoke coffee create app/assets/javascripts/store.js.coffee invoke scss create app/assets/stylesheets/store.css.scss In config/routes.rb Include the rout to store->index Depot::Application.routes.draw do get “store/index” resources :products # … # You can have the root of your site routed with “root” # just remember to delete public/index.html. # root :to => “welcome#index” root :to => ‘store#index’ , :as => ‘store’ # end

Instead localhost:3000/store/index with this root, store/index is accessed using localhost:3000/store/

In depot_d/app/controllers/store_controller.rb class StoreController < ApplicationController def index @products = Product.all end end

Include a default_scope to define the order of each query

depot_d/app/models/product.rb class Product < ActiveRecord::Base default_scope :order => ‘title’ # validation end

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

change the depot/app/views/layouts/application.html.erb

The CSS
	create a file public/stylesheets/depot.css

Using Helper to format price
	In index.html.erb
		<span class="price"><%= number_to_currency(product.price) %></span>

	put more test in products_controller_test.rb

Chart Creation $ rails generate scaffold cart invoke active_record create db/migrate/20131226000221_create_carts.rb create app/models/cart.rb invoke test_unit create test/models/cart_test.rb create test/fixtures/carts.yml invoke resource_route 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/controllers/carts_controller_test.rb invoke helper create app/helpers/carts_helper.rb invoke test_unit create test/helpers/carts_helper_test.rb invoke jbuilder create app/views/carts/index.json.jbuilder create app/views/carts/show.json.jbuilder 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

$ rake db:migrate

Change application_controller.rb to get the cart from session.

Create the line_item using scaffold. A connection between product and cart

$ rails generate scaffold line_item product_id:integer cart_id:integer

$ rake db:migrate

In app/models/cart.rb class Cart < ActiveRecord::Base has_many :line_items, :dependent => :destroy end In app/models/line_item.rb class LineItem < ActiveRecord::Base belongs_to :product belongs_to :cart end In app/models/producs.rb class Product < ActiveRecord::Base default_scope :order => ‘title’ has_many :line_items before_destroy :ensure_not_referenced_by_any_line_item # ensure that there are no line items referencing this product def ensure_not_referenced_by_any_line_item if line_items.count.zero? return true else errors.add(:base, ‘Line Items present’ ) return false end end Include link to add to cart in store/index.html.erb <div class=“price_line” > <span class=“price” ><%= number_to_currency(product.price) %></span> <%= button_to ‘Add to Cart’ , line_items_path(:product_id => product) %> </div>

In controllers/line_items_controller.rb, include the method to create.

A Smarter cat $ rails generate migration add_quantity_to_line_item quantity:integer invoke active_record create db/migrate/20131226042106_add_quantity_to_line_item.rb Create a migration file to add quality to line_item. Add the quality column. class AddQuantityToLineItem < ActiveRecord::Migration def self.up add_column :line_items, :quantity, :integer, :default => 1 end def self.down remove_column :line_items, :quantity end end

Include a add_product method to the Cart in models/cart.rb def add_product(product_id) current_item = line_items.where(:product_id => product_id).first if current_item current_item.quantity += 1 else current_item = line_items.build(:product_id => product_id) end current_item end

Modify the controller/create of controllers/line_items_controller.rb def create @cart = current_cart product = Product.find(params) @line_item = @cart.add_product(product.id) respond_to do |format| if @line_item.save format.html { redirect_to(@line_item.cart, :notice => ‘Line item was successfully created.’ ) } format.xml { render :xml => @line_item, :status => :created, :location => @line_item } else format.html { render :action => “new” } format.xml { render :xml => @line_item.errors, :status => :unprocessable_entity } end end end

and the carts/show.html.erb to reflect the change of quantity <h2>Your Pragmatic Cart</h2> <ul> <% @cart.line_items.each do |item| %> <li><%= item.quantity %> &times; <%= item.product.title %></li> <% end %> </ul>

Create a new migrate to remove the items already created and recreate with the quantity $ rails generate migration combine_items_in_cart invoke active_record create db/migrate/20131226045904_combine_items_in_cart.rb

And create this methods def self.up # replace multiple items for a single product in a cart with a single item Cart.all.each do |cart| # count the number of each product in the cart sums = cart.line_items.group(:product_id).sum(:quantity) sums.each do |product_id, quantity| if quantity > 1 # remove individual items cart.line_items.where(:product_id=>product_id).delete_all # replace with a single item cart.line_items.create(:product_id=>product_id, :quantity=>quantity) end end end end

$ rake db:migrate

To handle with erros Change the cart_controller to receiver wrong product id. def show begin @cart = Cart.find(params) rescue ActiveRecord::RecordNotFound logger.error “Attempt to access invalid cart #{params}” redirect_to store_url, :notice => ‘Invalid cart’ else respond_to do |format| format.html # show.html.erb format.xml { render :xml => @cart } end end end To empty cart In cat/show.html.erb <%= button_to ‘Empty cart’ , @cart, :method => :delete, :confirm => ‘Are you sure?’ %>

In controllers/carts_controller.rb Empty the cart def destroy @cart = current_cart @cart.destroy session = nil respond_to do |format| format.html { redirect_to(store_url, :notice => ‘Your cart is currently empty’ ) } format.xml { head :ok } end end

Add a Dash of Ajax Include partials carts/_cart.html.erb

line_item/_line_item.html.erb <% if line_item == @current_item %> <tr id=“current_item” > <% else %> <tr> <% end %> <td><%= line_item.quantity %>&times;</td> <td><%= line_item.product.title %></td> <td class=“item_price” ><%= number_to_currency(line_item.total_price) %></td> </tr> In store/index.html.erb <%= button_to ‘Add to Cart’ , line_items_path(:product_id => product), :remote => true %> Change the line_items_controller.rb to receive the ajax and send to a js format.js { @current_item = @line_item } And create a views/line_items/create.js.rjs page.replace_html(‘cart’ , render(@cart)) page.visual_effect :blind_down if @cart.total_items == 1 page.visual_effect :highlight, :startcolor => “#88ff88”, :endcolor => “#114411”

in layouts/application.html.erb

Check out git checkout -b checkout

Product Cart -> Order \ / Line_Item

$ rails generate scaffold order name:string address:text email:string pay_type:string invoke active_record

   create    db/migrate/20131230025845_create_orders.rb
   create    app/models/order.rb
   invoke    test_unit
   create      test/models/order_test.rb
   create      test/fixtures/orders.yml
   invoke  resource_route
    route    resources :orders
   invoke  scaffold_controller
   create    app/controllers/orders_controller.rb
   invoke    erb
   create      app/views/orders
   create      app/views/orders/index.html.erb
   create      app/views/orders/edit.html.erb
   create      app/views/orders/show.html.erb
   create      app/views/orders/new.html.erb
   create      app/views/orders/_form.html.erb
   invoke    test_unit
   create      test/controllers/orders_controller_test.rb
   invoke    helper
   create      app/helpers/orders_helper.rb
   invoke      test_unit
   create        test/helpers/orders_helper_test.rb
   invoke    jbuilder
   create      app/views/orders/index.json.jbuilder
   create      app/views/orders/show.json.jbuilder
   invoke  assets
   invoke    coffee
   create      app/assets/javascripts/orders.js.coffee
   invoke    scss
   create      app/assets/stylesheets/orders.css.scss
   invoke  scss
identical    app/assets/stylesheets/scaffolds.css.scss

$ rails generate migration add_order_id_to_line_item order_id:integer invoke active_record

create    db/migrate/20131230025942_add_order_id_to_line_item.rb

$ rake db:migrate

Pagination in gemfile gem ‘will_paginate’, ‘>= 3.0.pre’ $ bundle install Create some orders in depot/script/load_orders.rb Order.transaction do (1..100).each do |i| Order.create(:name => “Customer #{i}” , :address => “ #{i} Main Street” , :email => “customer- #{i}@example.com” , :pay_type => “Check” ) end end $ rails runner script/load_orders.rb in controllers/orders_controller.rb def index @orders = Order.paginate :page=>params, :order=>‘created_at desc’ , :per_page => 10 respond_to do |format| format.html # index.html.erb format.xml { render :xml => @orders } end end in app/views/orders/index.html.erb <p><%= will_paginate @orders %></p>

Sending email Three parts configuring how e-mail is to be sent determining when to send the e-mail specifying what you want to say. Configuring in config/environments/development.rb config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { :address => “smtp.gmail.com” , :port => 587, :domain => “domain.of.sender.net” , :authentication => “plain” , :user_name => “dave” , :password => “secret” , :enable_starttls_auto => true } Send e-mail Generate the mailer that works like the Controller. Intead of rendering, it “mail :to” $ rails generate mailer Notifier order_received order_shipped

create app/mailers/notifier.rb

			  invoke  erb

create app/views/notifier create app/views/notifier/order_received.text.erb create app/views/notifier/order_shipped.text.erb invoke test_unit create test/mailers/notifier_test.rb In the created file app/mailers/notifier.rb class Notifier < ActionMailer::Base default :from => ‘Sam Ruby <depot@example.com>’ en.notifier.order_received.subject def order_received @greeting = “Hi” mail :to => “to@example.org” end def order_shipped @greeting = “Hi” mail :to => “to@example.org” end end E-mail template In app/vies/notifier/order_received.text.erb

Integration test $ rails generate integration_test user_stories invoke test_unit create test/integration/user_stories_test.rb

Logging in Adding Users Create model and database table to hold administrator, username and password Password will be stored in a 256-bit SHA2. $ rails generate scaffold user name:string hashed_password:string salt:string invoke active_record create db/migrate/20140103064302_create_users.rb create app/models/user.rb invoke test_unit create test/models/user_test.rb create test/fixtures/users.yml invoke resource_route route resources :users invoke scaffold_controller create app/controllers/users_controller.rb invoke erb create app/views/users create app/views/users/index.html.erb create app/views/users/edit.html.erb create app/views/users/show.html.erb create app/views/users/new.html.erb create app/views/users/_form.html.erb invoke test_unit create test/controllers/users_controller_test.rb invoke helper create app/helpers/users_helper.rb invoke test_unit create test/helpers/users_helper_test.rb invoke jbuilder create app/views/users/index.json.jbuilder create app/views/users/show.json.jbuilder invoke assets invoke coffee create app/assets/javascripts/users.js.coffee invoke scss create app/assets/stylesheets/users.css.scss invoke scss identical app/assets/stylesheets/scaffolds.css.scss

$ rake db:migrate

app/models/user.rb class User < ActiveRecord::Base validates :name, :presence => true, :uniqueness => true

validates :password, :confirmation => true attr_accessor :password_confirmation attr_reader :password

validate :password_must_be_present private def password_must_be_present errors.add(:password, “Missing password” ) unless hashed_password.present? end end

Authenticating Users $ rails generate controller sessions new create destroy identical app/controllers/sessions_controller.rb route get “sessions/destroy” route get “sessions/create” route get “sessions/new” invoke erb exist app/views/sessions identical app/views/sessions/new.html.erb identical app/views/sessions/create.html.erb identical app/views/sessions/destroy.html.erb invoke test_unit identical test/controllers/sessions_controller_test.rb invoke helper identical app/helpers/sessions_helper.rb invoke test_unit identical test/helpers/sessions_helper_test.rb invoke assets invoke coffee identical app/assets/javascripts/sessions.js.coffee invoke scss identical app/assets/stylesheets/sessions.css.scss

$ rails generate controller admin index create app/controllers/admin_controller.rb route get “admin/index” invoke erb create app/views/admin create app/views/admin/index.html.erb invoke test_unit create test/controllers/admin_controller_test.rb invoke helper create app/helpers/admin_helper.rb invoke test_unit create test/helpers/admin_helper_test.rb invoke assets invoke coffee create app/assets/javascripts/admin.js.coffee invoke scss create app/assets/stylesheets/admin.css.scss

In controllers/sessions_controller.rb def create if user = User.authenticate(params, params) session = user.id redirect_to admin_url else redirect_to login_url, :alert => “Invalid user/password combination” end end

Limiting Access In application_controller.rb before_filter :authorize

protected

			def authorize
  			unless User.find_by_id(session[:user_id])
    				redirect_to login_url, :notice => "Please log in"
  			end
			end

	If you don't want to pass this filter use:
		class StoreController < ApplicationController

skip_before_filter :authorize

class SessionsController < ApplicationController skip_before_filter :authorize

class CartsController < ApplicationController skip_before_filter :authorize, :only => [:create, :update, :destroy]

Internationalization $ git checkout -b i18n

create config/initializers/i18n.rb #encoding: utf-8 I18n.default_locale = :en LANGUAGES = [

  		['English' , 'en' ],
  		["Portugues".html_safe, 'pt' ]
		 ]

  in config/routes.rb
  scope '(:locale)' do

resources :users resources :orders resources :line_items resources :carts resources :products do get :who_bought, :on => :member end root :to => ‘store#index’ , :as => ‘store’ end

In application_controller.rb class ApplicationController < ActionController::Base before_filter :set_i18n_locale_from_params

protected def set_i18n_locale_from_params if params if I18n.available_locales.include?(params.to_sym) I18n.locale = params else flash.now[:notice] = “ #{params} translation not available” logger.error flash.now[:notice] end end end def default_url_options { :locale => I18n.locale } end end

In views/layouts/application.html.erb t helper will look for name in template that begins with “.” <%= @page_title || t(‘.title’ ) %>

Fill config/locales/en.yml config/locates/pt.yml

To change the locale in views/layouts/application.html.erb <%= form_tag store_path, :class => ‘locale’ do %> <%= select_tag ‘set_locale’ , options_for_select(LANGUAGES, I18n.locale.to_s), :onchange => ‘this.form.submit()’ %> <%= submit_tag ‘submit’ %> <%= javascript_tag “$$(‘.locale input’).each(Element.hide)” %> <% end %> in controllers/store_controller.rb def index

		if params[:set_locale]
  			redirect_to store_path(:locale => params[:set_locale])
	    else
  			@products = Product.all
  			@cart = current_cart
		end
	  end

Commiting $ git add . $ git commit -m “i18n” $ git checkout master $ git merge i18n

About

Web Shopping cart Application in Ruby on Rails

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors