Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

Rails Best Practices

143.288 Aufrufe

Veröffentlicht am

see http://ihower.tw/blog/archives/3075 , this's my talk at http://kungfurails.com and http://ruby.tw

Veröffentlicht in: Automobil
  • DOWNLOAD THIS BOOKS INTO AVAILABLE FORMAT (2019 Update) ......................................................................................................................... ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/ubg3cxe } ......................................................................................................................... Download Full EPUB Ebook here { https://tinyurl.com/ubg3cxe } ......................................................................................................................... Download Full doc Ebook here { https://tinyurl.com/ubg3cxe } ......................................................................................................................... Download PDF EBOOK here { https://tinyurl.com/ubg3cxe } ......................................................................................................................... Download EPUB Ebook here { https://tinyurl.com/ubg3cxe } ......................................................................................................................... Download doc Ebook here { https://tinyurl.com/ubg3cxe } ......................................................................................................................... .........................................................................................................................
       Antworten 
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier
  • DOWNLOAD THIS BOOKS INTO AVAILABLE FORMAT (2019 Update) ......................................................................................................................... ......................................................................................................................... Download Full PDF EBOOK here { https://soo.gd/irt2 } ......................................................................................................................... Download Full EPUB Ebook here { https://soo.gd/irt2 } ......................................................................................................................... Download Full doc Ebook here { https://soo.gd/irt2 } ......................................................................................................................... Download PDF EBOOK here { https://soo.gd/irt2 } ......................................................................................................................... Download EPUB Ebook here { https://soo.gd/irt2 } ......................................................................................................................... Download doc Ebook here { https://soo.gd/irt2 } ......................................................................................................................... ......................................................................................................................... ................................................................................................................................... eBook is an electronic version of a traditional print book THIS can be read by using a personal computer or by using an eBook reader. (An eBook reader can be a software application for use on a computer such as Microsoft's free Reader application, or a book-sized computer THIS is used solely as a reading device such as Nuvomedia's Rocket eBook.) Users can purchase an eBook on diskette or CD, but the most popular method of getting an eBook is to purchase a downloadable file of the eBook (or other reading material) from a Web site (such as Barnes and Noble) to be read from the user's computer or reading device. Generally, an eBook can be downloaded in five minutes or less ......................................................................................................................... .............. Browse by Genre Available eBooks .............................................................................................................................. Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, ......................................................................................................................... ......................................................................................................................... .....BEST SELLER FOR EBOOK RECOMMEND............................................................. ......................................................................................................................... Blowout: Corrupted Democracy, Rogue State Russia, and the Richest, Most Destructive Industry on Earth,-- The Ride of a Lifetime: Lessons Learned from 15 Years as CEO of the Walt Disney Company,-- Call Sign Chaos: Learning to Lead,-- StrengthsFinder 2.0,-- Stillness Is the Key,-- She Said: Breaking the Sexual Harassment Story THIS Helped Ignite a Movement,-- Atomic Habits: An Easy & Proven Way to Build Good Habits & Break Bad Ones,-- Everything Is Figureoutable,-- What It Takes: Lessons in the Pursuit of Excellence,-- Rich Dad Poor Dad: What the Rich Teach Their Kids About Money THIS the Poor and Middle Class Do Not!,-- The Total Money Makeover: Classic Edition: A Proven Plan for Financial Fitness,-- Shut Up and Listen!: Hard Business Truths THIS Will Help You Succeed, ......................................................................................................................... .........................................................................................................................
       Antworten 
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier
  • DOWNLOAD THIS BOOKS INTO AVAILABLE FORMAT (2019 Update) ......................................................................................................................... ......................................................................................................................... Download Full PDF EBOOK here { https://soo.gd/irt2 } ......................................................................................................................... Download Full EPUB Ebook here { https://soo.gd/irt2 } ......................................................................................................................... Download Full doc Ebook here { https://soo.gd/irt2 } ......................................................................................................................... Download PDF EBOOK here { https://soo.gd/irt2 } ......................................................................................................................... Download EPUB Ebook here { https://soo.gd/irt2 } ......................................................................................................................... Download doc Ebook here { https://soo.gd/irt2 } ......................................................................................................................... ......................................................................................................................... ................................................................................................................................... eBook is an electronic version of a traditional print book THIS can be read by using a personal computer or by using an eBook reader. (An eBook reader can be a software application for use on a computer such as Microsoft's free Reader application, or a book-sized computer THIS is used solely as a reading device such as Nuvomedia's Rocket eBook.) Users can purchase an eBook on diskette or CD, but the most popular method of getting an eBook is to purchase a downloadable file of the eBook (or other reading material) from a Web site (such as Barnes and Noble) to be read from the user's computer or reading device. Generally, an eBook can be downloaded in five minutes or less ......................................................................................................................... .............. Browse by Genre Available eBooks .............................................................................................................................. Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, ......................................................................................................................... ......................................................................................................................... .....BEST SELLER FOR EBOOK RECOMMEND............................................................. ......................................................................................................................... Blowout: Corrupted Democracy, Rogue State Russia, and the Richest, Most Destructive Industry on Earth,-- The Ride of a Lifetime: Lessons Learned from 15 Years as CEO of the Walt Disney Company,-- Call Sign Chaos: Learning to Lead,-- StrengthsFinder 2.0,-- Stillness Is the Key,-- She Said: Breaking the Sexual Harassment Story THIS Helped Ignite a Movement,-- Atomic Habits: An Easy & Proven Way to Build Good Habits & Break Bad Ones,-- Everything Is Figureoutable,-- What It Takes: Lessons in the Pursuit of Excellence,-- Rich Dad Poor Dad: What the Rich Teach Their Kids About Money THIS the Poor and Middle Class Do Not!,-- The Total Money Makeover: Classic Edition: A Proven Plan for Financial Fitness,-- Shut Up and Listen!: Hard Business Truths THIS Will Help You Succeed, ......................................................................................................................... .........................................................................................................................
       Antworten 
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier
  • Visit Here to Read This eBook === http://letobodome.best/2247078125-Code-de-la-route-comment.html
       Antworten 
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier
  • accessibility Books Library allowing access to top content, including thousands of title from favorite author, plus the ability to read or download a huge selection of books for your pc or smartphone within minutes.........ACCESS WEBSITE Over for All Ebooks ..... (Unlimited) ......................................................................................................................... Download FULL PDF EBOOK here { http://bit.ly/2m6jJ5M } .........................................................................................................................
       Antworten 
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier

Rails Best Practices

  1. Rails Best Practices ihower@gmail.com As this slide writing, the current Rails version is 2.3.4
  2. Who am I ? • a.k.a. ihower • http://ihower.tw • http://twitter.com/ihower • http://github.com/ihower • (Hsinchu, Taiwan) • ( ) • http://handlino.com • http://registrano.com
  3. Ruby Taiwan http://ruby.tw
  4. Agenda • Concept: What’s good code? • Move Code from Controller to Model • RESTful best practices • Model best practices • Controller best practices • View best practices
  5. Warning! you should have testing before modify!
  6. Best Practice Lesson 0: Concepts
  7. Why best practices? • Large & complicated application • Team & different coding style
  8. Your code become... • (Rigidity) • (Fragility) • (Immobility) • (Viscosity) • (Needless Complexity) • (Needless Repetition) • (Opacity) Agile Software Development: Principles, Patterns, and Practices
  9. We need good code:
  10. What’s Good code? • Readability • Flexibility • Effective • Maintainability • Consistency • Testability
  11. So, What we can do?
  12. Best Practice Lesson 1: Move code from Controller to Model action code 15 http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model
  13. Before 1.Move finder to named_scope class PostsController < ApplicationController def index @public_posts = Post.find(:all, :conditions => { :state => 'public' }, :limit => 10, :order => 'created_at desc') @draft_posts = Post.find(:all, :conditions => { :state => 'draft' }, :limit => 10, :order => 'created_at desc') end end
  14. After 1.Move finder to named_scope class UsersController < ApplicationController def index @published_post = Post.published @draft_post = Post.draft end end class Post < ActiveRecord::Base named_scope :published, :conditions => { :state => 'published' }, :limit => 10, :order => 'created_at desc') named_scope :draft, :conditions => { :state => 'draft' }, :limit => 10, :order => 'created_at desc') end
  15. Before 2. Use model association class PostsController < ApplicationController def create @post = Post.new(params[:post]) @post.user_id = current_user.id @post.save end end
  16. After 2. Use model association class PostsController < ApplicationController def create @post = current_user.posts.build(params[:post]) @post.save end end class User < ActiveRecord::Base has_many :posts end
  17. 3. Use scope access Before class PostsController < ApplicationController def edit @post = Post.find(params[:id) if @post.current_user != current_user flash[:warning] = 'Access denied' redirect_to posts_url end end end
  18. 3. Use scope access After class PostsController < ApplicationController def edit # raise RecordNotFound exception (404 error) if not found @post = current_user.posts.find(params[:id) end end
  19. Before 4. Add model virtual attribute <% form_for @user do |f| %> <%= text_filed_tag :full_name %> <% end %> class UsersController < ApplicationController def create @user = User.new(params[:user) @user.first_name = params[:full_name].split(' ', 2).first @user.last_name = params[:full_name].split(' ', 2).last @user.save end end
  20. After 4. Add model virtual attribute class User < ActiveRecord::Base def full_name [first_name, last_name].join(' ') end def full_name=(name) split = name.split(' ', 2) self.first_name = split.first self.last_name = split.last end end example code from http://railscasts.com/episodes/16-virtual-attributes
  21. After <% form_for @user do |f| %> <%= f.text_field :full_name %> <% end %> class UsersController < ApplicationController def create @user = User.create(params[:user) end end example code from http://railscasts.com/episodes/16-virtual-attributes
  22. 5. Use model callback Before <% form_for @post do |f| %> <%= f.text_field :content %> <%= check_box_tag 'auto_tagging' %> <% end %> class PostController < ApplicationController def create @post = Post.new(params[:post]) if params[:auto_tagging] == '1' @post.tags = AsiaSearch.generate_tags(@post.content) else @post.tags = "" end @post.save end end
  23. After 5. Use model callback class Post < ActiveRecord::Base attr_accessor :auto_tagging before_save :generate_taggings private def generate_taggings return unless auto_tagging == '1' self.tags = Asia.search(self.content) end end
  24. After <% form_for :note, ... do |f| %> <%= f.text_field :content %> <%= f.check_box :auto_tagging %> <% end class PostController < ApplicationController def create @post = Post.new(params[:post]) @post.save end end
  25. 6. Replace Complex Creation Before with Factory Method class InvoiceController < ApplicationController def create @invoice = Invoice.new(params[:invoice]) @invoice.address = current_user.address @invoice.phone = current_user.phone @invoice.vip = ( @invoice.amount > 1000 ) if Time.now.day > 15 @invoice.delivery_time = Time.now + 2.month else @invoice.delivery_time = Time.now + 1.month end @invoice.save end end
  26. 6. Replace Complex Creation After with Factory Method class Invoice < ActiveRecord::Base def self.new_by_user(params, user) invoice = self.new(params) invoice.address = user.address invoice.phone = user.phone invoice.vip = ( invoice.amount > 1000 ) if Time.now.day > 15 invoice.delivery_time = Time.now + 2.month else invoice.delivery_time = Time.now + 1.month end end end
  27. After class InvoiceController < ApplicationController def create @invoice = Invoice.new_by_user(params[:invoice], current_user) @invoice.save end end
  28. 7. Move Model Logic into the Before Model class PostController < ApplicationController def publish @post = Post.find(params[:id]) @post.update_attribute(:is_published, true) @post.approved_by = current_user if @post.create_at > Time.now - 7.days @post.popular = 100 else @post.popular = 0 end redirect_to post_url(@post) end end
  29. 7. Move Model Logic into the After Model class Post < ActiveRecord::Base def publish self.is_published = true self.approved_by = current_user if self.create_at > Time.now-7.days self.popular = 100 else self.popular = 0 end end end
  30. After class PostController < ApplicationController def publish @post = Post.find(params[:id]) @post.publish redirect_to post_url(@post) end end
  31. 8. model.collection_model_ids (many-to-many) class User < ActiveRecord::Base has_many :user_role_relationship has_many :roles, :through => :user_role_relationship end class UserRoleRelationship < ActiveRecord::Base belongs_to :user belongs_to :role end class Role < ActiveRecord::Base end
  32. Before <% form_for @user do |f| %> <%= f.text_field :email %> <% for role in Role.all %> <%= check_box_tag 'role_id[]', role.id, @user.roles.include?(role) %> <%= role.name %> <% end %> <% end %> class User < ApplicationController def update @user = User.find(params[:id]) if @user.update_attributes(params[:user]) @user.roles.delete_all (params[:role_id] || []).each { |i| @user.roles << Role.find(i) } end end end
  33. After <% form_for @user do |f| %> <% for role in Role.all %> <%= check_box_tag 'user[role_ids][]', role.id, @user.roles.include?(role) <%= role.name %> <% end %> <%= hidden_field_tag 'user[role_ids][]', '' %> <% end %> class User < ApplicationController def update @user = User.find(params[:id]) @user.update_attributes(params[:user]) # @user.role_ids = params[:user][:role_ids] end end
  34. 9. Nested Model Forms (one-to-one) Before class Product < ActiveRecord::Base has_one :detail end class Detail < ActiveRecord::Base belongs_to :product end <% form_for :product do |f| %> <%= f.text_field :title %> <% fields_for :detail do |detail| %> <%= detail.text_field :manufacturer %> <% end %> <% end %>
  35. Before class Product < ApplicationController def create @product = Product.new(params[:product]) @details = Detail.new(params[:detail]) Product.transaction do @product.save! @details.product = @product @details.save! end end end example code from Agile Web Development with Rails 3rd.
  36. 9. Nested Model Forms (one-to-one) After Rails 2.3 new feature class Product < ActiveRecord::Base has_one :detail accepts_nested_attributes_for :detail end <% form_for :product do |f| %> <%= f.text_field :title %> <% f.fields_for :detail do |detail| %> <%= detail.text_field :manufacturer %> <% end %> <% end
  37. After class Product < ApplicationController def create @product = Product.new(params[:product]) @product.save end end
  38. 10. Nested Model Forms (one-to-many) class Project < ActiveRecord::Base has_many :tasks accepts_nested_attributes_for :tasks end class Task < ActiveRecord::Base belongs_to :project end <% form_for @project do |f| %> <%= f.text_field :name %> <% f.fields_for :tasks do |tasks_form| %> <%= tasks_form.text_field :name %> <% end %> <% end %>
  39. Nested Model Forms before Rails 2.3 ? • Ryan Bates’s series of railscasts on complex forms • http://railscasts.com/episodes/75-complex-forms-part-3 • Recipe 13 in Advanced Rails Recipes book
  40. Best Practice Lesson 2: RESTful RESTful conventions
  41. Why RESTful? RESTful help you to organize/name controllers, routes and actions in standardization way
  42. Before class EventsController < ApplicationController def index def white_member_list def watch_list def feeds end end end end def show def black_member_list def add_favorite def add_comment end end end end def create def deny_user def invite def show_comment end end end end def update def allow_user def join def destroy_comment end end end end def destroy def edit_managers def leave def edit_comment end end end end def approve_comment def set_user_as_manager end end def set_user_as_member end end
  43. After class EventsController < ApplicationController def index; end def show; end end class CommentsControlers < ApplicationController def index; end def create; end def destroy; end end def FavoriteControllers < ApplicationController def create; end def destroy; end end class EventMembershipsControlers < ApplicationController def create; end def destroy; end end
  44. Before 1. Overuse route customizations map.resources :posts, :member => { :comments => :get, :create_comment => :post, :update_comment => :post, :delete_comment => :post }
  45. After 1. Overuse route customizations Find another resources map.resources :posts do |post| post.resources :comments end
  46. Suppose we has a event model... class Event < ActiveRecord::Base has_many :attendee has_one :map has_many :memberships has_many :users, :through => :memberships end
  47. Can you answer how to design your resources ? • manage event attendees (one-to-many) • manage event map (one-to-one) • manage event memberships (many-to-many) • operate event state: open or closed • search events • sorting events • event admin interface
  48. Learn RESTful design my slide about restful: http://www.slideshare.net/ihower/practical-rails2-350619
  49. Before 2. Needless deep nesting : Never more than one level map.resources :posts do |post| post.resources :comments do |comment| comment.resources :favorites end end <%= link_to post_comment_favorite_path(@post, @comment, @favorite) %>
  50. After 2. Needless deep nesting : Never more than one level map.resources :posts do |post| post.resources :comments end map.resources :comments do |comment| comment.resources :favorites end <%= link_to comment_favorite_path(@comment, @favorite) %>
  51. Before 3. Not use default route map.resources :posts, :member => { :push => :post } map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format'
  52. After 3. Not use default route map.resources :posts, :member => { :push => :post } #map.connect ':controller/:action/:id' #map.connect ':controller/:action/:id.:format' map.connect 'special/:action/:id', :controller => 'special'
  53. Best Practice Lesson 3: Model
  54. Before 1. Keep Finders on Their Own Model class Post < ActiveRecord::Base has_many :comments def find_valid_comments self.comment.find(:all, :conditions => { :is_spam => false }, :limit => 10) end end class Comment < ActiveRecord::Base belongs_to :post end class CommentsController < ApplicationController def index @comments = @post.find_valid_comments end end
  55. After 1. Keep Finders on Their Own Model class Post < ActiveRecord::Base has_many :comments end class Comment < ActiveRecord::Base belongs_to :post named_scope :only_valid, :conditions => { :is_spam => false } named_scope :limit, lambda { |size| { :limit => size } } end class CommentsController < ApplicationController def index @comments = @post.comments.only_valid.limit(10) end end
  56. Before 2. Love named_scope class PostController < ApplicationController def search conditions = { :title => "%#{params[:title]}%" } if params[:title] conditions.merge!{ :content => "%#{params[:content]}%" } if params[:content] case params[:order] when "title" : order = "title desc" when "created_at" : order = "created_at" end if params[:is_published] conditions.merge!{ :is_published => true } end @posts = Post.find(:all, :conditions => conditions, :order => order, :limit => params[:limit]) end end example code from Rails Antipatterns book
  57. After 2. Love named_scope class Post < ActiveRecord::Base named_scope :matching, lambda { |column, value| return {} if value.blank? { :conditions => ["#{column} like ?", "%#{value}%"] } } named_scope :order, lambda { |order| { :order => case order when "title" : "title desc" when "created_at" : "created_at" end } } end
  58. After class PostController < ApplicationController def search @posts = Post.matching(:title, params[:title]) .matching(:content, params[:content]) .order(params[:order]) end end
  59. Before 3. the Law of Demeter class Invoice < ActiveRecord::Base belongs_to :user end <%= @invoice.user.name %> <%= @invoice.user.address %> <%= @invoice.user.cellphone %>
  60. After 3. the Law of Demeter class Invoice < ActiveRecord::Base belongs_to :user delegate :name, :address, :cellphone, :to => :user, :prefix => true end <%= @invoice.user_name %> <%= @invoice.user_address %> <%= @invoice.user_cellphone %>
  61. 4. DRY: Metaprogramming Before class Post < ActiveRecord::Base validate_inclusion_of :status, :in => ['draft', 'published', 'spam'] def self.all_draft find(:all, :conditions => { :status => 'draft' } end def self.all_published find(:all, :conditions => { :status => 'published' } end def self.all_spam find(:all, :conditions => { :status => 'spam' } end def draft? self.stats == 'draft' end def published? self.stats == 'published' end def spam? self.stats == 'spam' end end
  62. 4. DRY: Metaprogramming After class Post < ActiveRecord::Base STATUSES = ['draft', 'published', 'spam'] validate_inclusion_of :status, :in => STATUSES class << self STATUSES.each do |status_name| define_method "all_#{status}" do find(:all, :conditions => { :status => status_name } end end end STATUSES.each do |status_name| define_method "#{status_name}?" do self.status == status_name end end end
  63. Breaking Up Models Model
  64. Before 5. Extract into Module class User < ActiveRecord::Base validates_presence_of :cellphone before_save :parse_cellphone def parse_cellphone # do something end end
  65. After # /lib/has_cellphone.rb module HasCellphone def self.included(base) base.validates_presence_of :cellphone base.before_save :parse_cellphone base.send(:include,InstanceMethods) base.send(:extend, ClassMethods) end module InstanceMethods def parse_cellphone # do something end end module ClassMethods end end
  66. After class User < ActiveRecord::Base include HasCellphone end
  67. Before 6. Extract to composed class # == Schema Information # address_city :string(255) # address_street :string(255) class Customer < ActiveRecord::Base def adddress_close_to?(other_customer) address_city == other_customer.address_city end def address_equal(other_customer) address_street == other_customer.address_street && address_city == other_customer.address_city end end
  68. 6. Extract to composed class After (value object) class Customer < ActiveRecord::Base composed_of :address, :mapping => [ %w(address_street street), %w(address_city city) ] end class Address attr_reader :street, :city def initialize(street, city) @street, @city = street, city end def close_to?(other_address) city == other_address.city end def ==(other_address) city == other_address.city && street == other_address.street end end example code from Agile Web Development with Rails 3rd.
  69. Before 7. Use Observer class Project < ActiveRecord::Base after_create :send_create_notifications private def send_create_notifications self.members.each do |member| ProjectNotifier.deliver_notification(self, member) end end end
  70. After 7. Use Observer class Project < ActiveRecord::Base # nothing here end # app/observers/project_notification_observer.rb class ProjectNotificationObserver < ActiveRecord::Observer observe Project def after_create(project) project.members.each do |member| ProjectMailer.deliver_notice(project, member) end end end
  71. Best Practice Lesson 4: Migration
  72. Before 1. Isolating Seed Data class CreateRoles < ActiveRecord::Migration def self.up create_table "roles", :force => true do |t| t.string :name end ["admin", "author", "editor","account"].each do |name| Role.create!(:name => name) end end def self.down drop_table "roles" end end
  73. After 1. Isolating Seed Data # /db/seeds.rb (Rails 2.3.4) ["admin", "author", "editor","account"].each do |name| Role.create!(:name => name) end rake db:seed
  74. After # /lib/tasks/dev.rake (before Rails 2.3.4) namespace :dev do desc "Setup seed data" task :setup => :environment do ["admin", "author", "editor","account"].each do |name| Role.create!(:name => name) end end end rake dev:setup
  75. Before 2. Always add DB index class CreateComments < ActiveRecord::Migration def self.up create_table "comments", :force => true do |t| t.string :content t.integer :post_id t.integer :user_id end end def self.down drop_table "comments" end end
  76. After 2. Always add DB index class CreateComments < ActiveRecord::Migration def self.up create_table "comments", :force => true do |t| t.string :content t.integer :post_id t.integer :user_id end add_index :comments, :post_id add_index :comments, :user_id end def self.down drop_table "comments" end end
  77. Best Practice Lesson 5: Controller
  78. 1. Use before_filter Before class PostController < ApplicationController def show @post = current_user.posts.find(params[:id] end def edit @post = current_user.posts.find(params[:id] end def update @post = current_user.posts.find(params[:id] @post.update_attributes(params[:post]) end def destroy @post = current_user.posts.find(params[:id] @post.destroy end end
  79. 1. Use before_filter After class PostController < ApplicationController before_filter :find_post, :only => [:show, :edit, :update, :destroy] def update @post.update_attributes(params[:post]) end def destroy @post.destroy end protected def find_post @post = current_user.posts.find(params[:id]) end end
  80. Before 2. DRY Controller class PostController < ApplicationController def index def edit @posts = Post.all @post = Post.find(params[:id) end end def show def update @post = Post.find(params[:id) @post = Post.find(params[:id) end @post.update_attributes(params[:post]) redirect_to post_path(@post) def new end @post = Post.new end def destroy @post = Post.find(params[:id) def create @post.destroy @post.create(params[:post] redirect_to posts_path redirect_to post_path(@post) end end end
  81. After 2. DRY Controller http://github.com/josevalim/inherited_resources class PostController < InheritedResources::Base # magic!! nothing here! end
  82. After 2. DRY Controller class PostController < InheritedResources::Base # if you need customize redirect url def create create! do |success, failure| seccess.html { redirect_to post_url(@post) } failure.html { redirect_to root_url } end end end
  83. DRY Controller Debate!! • You lose intent and readability • Deviating from standards makes it harder to work with other programmers • Upgrading rails from http://www.binarylogic.com/2009/10/06/discontinuing-resourcelogic/
  84. Best Practice Lesson 6: View
  85. Never logic code in Views
  86. 1. Move code into controller Before <% @posts = Post.find(:all) %> <% @posts.each do |post| %> <%=h post.title %> <%=h post.content %> <% end %> After class PostsController < ApplicationController def index @posts = Post.find(:all) end end
  87. 2. Move code into model Before <% if current_user && (current_user == @post.user || @post.editors.include?(current_user) %> <%= link_to 'Edit this post', edit_post_url(@post) %> <% end %> <% if @post.editable_by?(current_user) %> After <%= link_to 'Edit this post', edit_post_url(@post) %> <% end %> class Post < ActiveRecord::Base def ediable_by?(user) user && ( user == self.user || self.editors.include?(user) end end
  88. Before 3. Move code into helper <%= select_tag :state, options_for_select( [[t(:draft),"draft" ], [t(:published),"published"]], params[:default_state] ) %> After <%= select_tag :state, options_for_post_state(params[:default_state]) %> # /app/helpers/posts_helper.rb def options_for_post_state(default_state) options_for_select( [[t(:draft),"draft" ],[t(:published),"published"]], default_state ) end
  89. 4. Replace instance variable with local variable class Post < ApplicationController def show @post = Post.find(params[:id) end end Before <%= render :partial => "sidebar" %> After <%= render :partial => "sidebar", :locals => { :post => @post } %>
  90. Before 5. Use Form Builder <% form_for @post do |f| %> <p> <%= f.label :title, t("post.title") %> <br> <%= f.text_field :title %> </p> <p> <%= f.label :content %> <br> <%= f.text_area :content, :size => '80x20' %> </p> <p> <%= f.submit t("submit") %> </p> <% end %>
  91. After 5. Use Form Builder <% my_form_for @post do |f| %> <%= f.text_field :title, :label => t("post.title") %> <%= f.text_area :content, :size => '80x20', :label => t("post.content") %> <%= f.submit t("submit") %> <% end %>
  92. After module ApplicationHelper def my_form_for(*args, &block) options = args.extract_options!.merge(:builder => LabeledFormBuilder) form_for(*(args + [options]), &block) end end class MyFormBuilder < ActionView::Helpers::FormBuilder %w[text_field text_area].each do |method_name| define_method(method_name) do |field_name, *args| @template.content_tag(:p, field_label(field_name, *args) + "<br />" + field_error(field_name) + super) end end def submit(*args) @template.content_tag(:p, super) end end
  93. 6. Organize Helper files # app/helpers/user_posts_helper.rb Before # app/helpers/author_posts_helper.rb # app/helpers/editor_posts_helper.rb # app/helpers/admin_posts_helper.rb class ApplicationController < ActionController::Base After helper :all # include all helpers, all the time end # app/helpers/posts_helper.rb
  94. 7. Learn Rails Helpers • Learn content_for and yield • Learn how to pass block parameter in helper • my slide about helper: http://www.slideshare.net/ihower/building-web-interface-on-rails • Read Rails helpers source code • /actionpack-x.y.z/action_view/helpers/*
  95. Best Practice Lesson 7: Code Refactoring
  96. We have Ruby edition now!! Must read it!
  97. Reference: : http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model http://www.matthewpaulmoore.com/ruby-on-rails-code-quality-checklist http://www.chadfowler.com/2009/4/1/20-rails-development-no-no-s : Pragmatic Patterns of Ruby on Rails Advanced Active Record Techniques Best Practice Refactoring Chad Pytel Refactoring Your Rails Application RailsConf 2008 The Worst Rails Code You've Ever Seen Obie Fernandez Mastering Rails Forms screencasts with Ryan Bates : Agile Software Development: Principles, Patterns, and Practices AWDwR 3rd The Rails Way 2nd. Advanced Rails Recipes Refactoring Ruby Edition Ruby Best Practices Enterprise Rails Rails Antipatterns Rails Rescue Handbook Code Review (PeepCode) Plugin Patterns (PeepCode)
  98. Thank you.

×