Rails Best PracticesFriday, August 31, 12
Why best practices?Friday, August 31, 12
Why best practices?        01 MaintainabilityFriday, August 31, 12
Why best practices?        01 Maintainability        02 DRY codeFriday, August 31, 12
Why best practices?        01 Maintainability        02 DRY code        03 Better delegationFriday, August 31, 12
Why best practices?        01 Maintainability        02 DRY code        03 Better delegation        04 It just worksFriday...
Fat models, skinny controllersFriday, August 31, 12
Fat models, skinny controllers      class TweetsController < ApplicationController          def index            if params...
Fat models, skinny controllers      class TweetsController < ApplicationController          def index            if params...
Fat models, skinny controllers      class TweetsController < ApplicationController          def index            if params...
Fat models, skinny controllers      class TweetsController < ApplicationController          def index            if params...
Fat models, skinny controllers      class TweetsController < ApplicationController          def index            if params...
Scope it outFriday, August 31, 12
Scope it out       class UsersController < ApplicationController           def show             @user = User.find(params[:...
Scope it out       class UsersController < ApplicationController           def show             @user = User.find(params[:...
Scope it out       class UsersController < ApplicationController           def show             @user = User.find(params[:...
Scope it out       class UsersController < ApplicationController           def show             @user = User.find(params[:...
Scope it out       class UsersController < ApplicationController           def show             @user = User.find(params[:...
Scope it out       class UsersController < ApplicationController           def show             @user = User.find(params[:...
Scope it out       class UsersController < ApplicationController           def show             @user = User.find(params[:...
SQL InjectionFriday, August 31, 12
SQL Injection     User.where("name = #{params[:search]}")Friday, August 31, 12
SQL Injection     User.where("name = #{params[:search]}")Friday, August 31, 12
SQL Injection     User.where("name = #{params[:search]}")      User.where("name = ?", "#{params[:search]}")Friday, August ...
SQL Injection     User.where("name = #{params[:search]}")      User.where("name = ?", "#{params[:search]}")       User.whe...
SQL Injection     User.where("name = #{params[:search]}")      User.where("name = ?", "#{params[:search]}")       User.whe...
Model without DB && REST      #encoding: utf-8                                    class ContactsController < ApplicationCo...
Model without DB && REST      #encoding: utf-8                                    class ContactsController < ApplicationCo...
Model without DB && REST      #encoding: utf-8                                    class ContactsController < ApplicationCo...
Model without DB && REST      #encoding: utf-8                                    class ContactsController < ApplicationCo...
N+1 Queries are not coolFriday, August 31, 12
N+1 Queries are not cool          def recent_followers            self.followers.recent.collect {|f| f.user.name }.to_sent...
N+1 Queries are not cool          def recent_followers            self.followers.recent.collect {|f| f.user.name }.to_sent...
N+1 Queries are not cool          def recent_followers            self.followers.recent.collect {|f| f.user.name }.to_sent...
N+1 Queries are not cool          def recent_followers            self.followers.recent.collect {|f| f.user.name }.to_sent...
N+1 Queries are not cool          def recent_followers            self.followers.recent.collect {|f| f.user.name }.to_sent...
N+1 Queries are not cool          def recent_followers            self.followers.recent.collect {|f| f.user.name }.to_sent...
N+1 Queries are not coolFriday, August 31, 12
N+1 Queries are not cool          def recent_followers            self.followers.recent.includes(:user).collect {|f| f.use...
N+1 Queries are not cool          def recent_followers            self.followers.recent.includes(:user).collect {|f| f.use...
N+1 Queries are not cool          def recent_followers            self.followers.recent.includes(:user).collect {|f| f.use...
N+1 Queries are not cool          def recent_followers            self.followers.recent.includes(:user).collect {|f| f.use...
N+1 Queries are not cool          def recent_followers            self.followers.recent.includes(:user).collect {|f| f.use...
Counter cache FTW!Friday, August 31, 12
Counter cache FTW!         <%= pluralize @user.tweets.length, tweet %>Friday, August 31, 12
Counter cache FTW!                                                          1. Select all tweets from user         <%= plu...
Counter cache FTW!                                                          1. Select all tweets from user         <%= plu...
Counter cache FTW!                                                          1. Select all tweets from user         <%= plu...
Counter cache FTW!                                                          1. Select all tweets from user         <%= plu...
Counter cache FTW!                                                          1. Select all tweets from user         <%= plu...
Counter cache FTW!                                                          1. Select all tweets from user         <%= plu...
Counter cache FTW!                                                          1. Select all tweets from user         <%= plu...
Counter cache FTW!                                                          1. Select all tweets from user         <%= plu...
Counter cache FTW!                                                          1. Select all tweets from user         <%= plu...
Counter cache FTW!                                                          1. Select all tweets from user         <%= plu...
Counter cache FTW!                                                          1. Select all tweets from user         <%= plu...
Counter cache FTW!                                                                   1. Select all tweets from user       ...
Rails Best PracticesFriday, August 31, 12
Upcoming SlideShare
Loading in...5
×

Rails Best Practices

1,879

Published on

Published in: Technology, Business
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,879
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
84
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Rails Best Practices

  1. 1. Rails Best PracticesFriday, August 31, 12
  2. 2. Why best practices?Friday, August 31, 12
  3. 3. Why best practices? 01 MaintainabilityFriday, August 31, 12
  4. 4. Why best practices? 01 Maintainability 02 DRY codeFriday, August 31, 12
  5. 5. Why best practices? 01 Maintainability 02 DRY code 03 Better delegationFriday, August 31, 12
  6. 6. Why best practices? 01 Maintainability 02 DRY code 03 Better delegation 04 It just worksFriday, August 31, 12
  7. 7. Fat models, skinny controllersFriday, August 31, 12
  8. 8. Fat models, skinny controllers class TweetsController < ApplicationController def index if params[:search].present? @tweets = Tweet.all else @tweets = Tweet.where("content LIKE ?", "%#{params[:search]}%") end end endFriday, August 31, 12
  9. 9. Fat models, skinny controllers class TweetsController < ApplicationController def index if params[:search].present? @tweets = Tweet.all else @tweets = Tweet.where("content LIKE ?", "%#{params[:search]}%") end end endFriday, August 31, 12
  10. 10. Fat models, skinny controllers class TweetsController < ApplicationController def index if params[:search].present? @tweets = Tweet.all else @tweets = Tweet.where("content LIKE ?", "%#{params[:search]}%") end end end class TweetsController < ApplicationController def index @tweets = Tweet.search(params) end endFriday, August 31, 12
  11. 11. Fat models, skinny controllers class TweetsController < ApplicationController def index if params[:search].present? @tweets = Tweet.all else @tweets = Tweet.where("content LIKE ?", "%#{params[:search]}%") end end end class TweetsController < ApplicationController def self.search(params= {}) if params[:search].present def index where("content LIKE ?", "%#{params[:search]}%") @tweets = Tweet.search(params) else end all end end endFriday, August 31, 12
  12. 12. Fat models, skinny controllers class TweetsController < ApplicationController def index if params[:search].present? @tweets = Tweet.all else @tweets = Tweet.where("content LIKE ?", "%#{params[:search]}%") end end end class TweetsController < ApplicationController def self.search(params= {}) if params[:search].present def index where("content LIKE ?", "%#{params[:search]}%") @tweets = Tweet.search(params) else end all end end endFriday, August 31, 12
  13. 13. Scope it outFriday, August 31, 12
  14. 14. Scope it out class UsersController < ApplicationController def show @user = User.find(params[:id]) @tweets = @user.tweets.where("retweets_count > 5").order(created_at DESC).limit(5) end endFriday, August 31, 12
  15. 15. Scope it out class UsersController < ApplicationController def show @user = User.find(params[:id]) @tweets = @user.tweets.where("retweets_count > 5").order(created_at DESC).limit(5) end endFriday, August 31, 12
  16. 16. Scope it out class UsersController < ApplicationController def show @user = User.find(params[:id]) @tweets = @user.tweets.where("retweets_count > 5").order(created_at DESC).limit(5) end endFriday, August 31, 12
  17. 17. Scope it out class UsersController < ApplicationController def show @user = User.find(params[:id]) @tweets = @user.tweets.where("retweets_count > 5").order(created_at DESC).limit(5) end end class UsersController < ApplicationController def show @user = User.find(params[:id]) @tweets = @user.tweets.with_many_retweets.recent.limit(5) end endFriday, August 31, 12
  18. 18. Scope it out class UsersController < ApplicationController def show @user = User.find(params[:id]) @tweets = @user.tweets.where("retweets_count > 5").order(created_at DESC).limit(5) end end class UsersController < ApplicationController def show @user = User.find(params[:id]) @tweets = @user.tweets.with_many_retweets.recent.limit(5) end endFriday, August 31, 12
  19. 19. Scope it out class UsersController < ApplicationController def show @user = User.find(params[:id]) @tweets = @user.tweets.where("retweets_count > 5").order(created_at DESC).limit(5) end end class Tweet < ActiveRecord::Base class UsersController < ApplicationController attr_accessible :content, :user_id def show belongs_to :user @user = User.find(params[:id]) @tweets = @user.tweets.with_many_retweets.recent.limit(5) scope :recent, order(created_at DESC) end scope :with_many_retweets, where("retweets_count > 5") end endFriday, August 31, 12
  20. 20. Scope it out class UsersController < ApplicationController def show @user = User.find(params[:id]) @tweets = @user.tweets.where("retweets_count > 5").order(created_at DESC).limit(5) end end class Tweet < ActiveRecord::Base class UsersController < ApplicationController attr_accessible :content, :user_id def show belongs_to :user @user = User.find(params[:id]) @tweets = @user.tweets.with_many_retweets.recent.limit(5) scope :recent, order(created_at DESC) end scope :with_many_retweets, where("retweets_count > 5") end endFriday, August 31, 12
  21. 21. SQL InjectionFriday, August 31, 12
  22. 22. SQL Injection User.where("name = #{params[:search]}")Friday, August 31, 12
  23. 23. SQL Injection User.where("name = #{params[:search]}")Friday, August 31, 12
  24. 24. SQL Injection User.where("name = #{params[:search]}") User.where("name = ?", "#{params[:search]}")Friday, August 31, 12
  25. 25. SQL Injection User.where("name = #{params[:search]}") User.where("name = ?", "#{params[:search]}") User.where(:name => params[:search])Friday, August 31, 12
  26. 26. SQL Injection User.where("name = #{params[:search]}") User.where("name = ?", "#{params[:search]}") User.where(:name => params[:search]) User.where("username = :login OR email = :login", {:login => params[:login]})Friday, August 31, 12
  27. 27. Model without DB && REST #encoding: utf-8 class ContactsController < ApplicationController class Contact def new include ActiveModel::Validations @contact = Contact.new include ActiveModel::Conversion end attr_accessor :name, :email, :message def create validates :name, :email, :company, :reason, @contact = Contact.new(params[:contact]) :message, :presence => true if @contact.valid? ContactMailer.contact_message(@contact).deliver def initialize(attributes = {}) redirect_to root_path, :notice => "Sweet!" attributes.each do |name, value| else send("#{name}=", value) render :new end end end end end def persisted? false end end REST: Don’t be too deep - /users/1/tweets/ 3/comments/2 Not using REST is ok tooFriday, August 31, 12
  28. 28. Model without DB && REST #encoding: utf-8 class ContactsController < ApplicationController class Contact def new include ActiveModel::Validations @contact = Contact.new include ActiveModel::Conversion end attr_accessor :name, :email, :message def create validates :name, :email, :company, :reason, @contact = Contact.new(params[:contact]) :message, :presence => true if @contact.valid? ContactMailer.contact_message(@contact).deliver def initialize(attributes = {}) redirect_to root_path, :notice => "Sweet!" attributes.each do |name, value| else send("#{name}=", value) render :new end end end end end def persisted? false end end REST: Don’t be too deep - /users/1/tweets/ 3/comments/2 Not using REST is ok tooFriday, August 31, 12
  29. 29. Model without DB && REST #encoding: utf-8 class ContactsController < ApplicationController class Contact def new include ActiveModel::Validations @contact = Contact.new include ActiveModel::Conversion end attr_accessor :name, :email, :message def create validates :name, :email, :company, :reason, @contact = Contact.new(params[:contact]) :message, :presence => true if @contact.valid? ContactMailer.contact_message(@contact).deliver def initialize(attributes = {}) redirect_to root_path, :notice => "Sweet!" attributes.each do |name, value| else send("#{name}=", value) render :new end end end end end def persisted? false end end REST: Don’t be too deep - /users/1/tweets/ 3/comments/2 Not using REST is ok tooFriday, August 31, 12
  30. 30. Model without DB && REST #encoding: utf-8 class ContactsController < ApplicationController class Contact def new include ActiveModel::Validations @contact = Contact.new include ActiveModel::Conversion end attr_accessor :name, :email, :message def create validates :name, :email, :company, :reason, @contact = Contact.new(params[:contact]) :message, :presence => true if @contact.valid? ContactMailer.contact_message(@contact).deliver def initialize(attributes = {}) redirect_to root_path, :notice => "Sweet!" attributes.each do |name, value| else send("#{name}=", value) render :new end end end end end def persisted? false end end REST: Don’t be too deep - /users/1/tweets/ 3/comments/2 Not using REST is ok tooFriday, August 31, 12
  31. 31. N+1 Queries are not coolFriday, August 31, 12
  32. 32. N+1 Queries are not cool def recent_followers self.followers.recent.collect {|f| f.user.name }.to_sentence endFriday, August 31, 12
  33. 33. N+1 Queries are not cool def recent_followers self.followers.recent.collect {|f| f.user.name }.to_sentence endFriday, August 31, 12
  34. 34. N+1 Queries are not cool def recent_followers self.followers.recent.collect {|f| f.user.name }.to_sentence endFriday, August 31, 12
  35. 35. N+1 Queries are not cool def recent_followers self.followers.recent.collect {|f| f.user.name }.to_sentence end => “Edo, Lentes, Javi”Friday, August 31, 12
  36. 36. N+1 Queries are not cool def recent_followers self.followers.recent.collect {|f| f.user.name }.to_sentence end => “Edo, Lentes, Javi” Select followers where user_id = 1 Select user where id=2 Select user where id=3 Select user where id=4 Select user where id=5 5 fat queriesFriday, August 31, 12
  37. 37. N+1 Queries are not cool def recent_followers self.followers.recent.collect {|f| f.user.name }.to_sentence end => “Edo, Lentes, Javi” Select followers where user_id = 1 Select user where id=2 Select user where id=3 Select user where id=4 Select user where id=5 5 fat queriesFriday, August 31, 12
  38. 38. N+1 Queries are not coolFriday, August 31, 12
  39. 39. N+1 Queries are not cool def recent_followers self.followers.recent.includes(:user).collect {|f| f.user.name }.to_sentence endFriday, August 31, 12
  40. 40. N+1 Queries are not cool def recent_followers self.followers.recent.includes(:user).collect {|f| f.user.name }.to_sentence end => “Edo, Lentes, Javi”Friday, August 31, 12
  41. 41. N+1 Queries are not cool def recent_followers self.followers.recent.includes(:user).collect {|f| f.user.name }.to_sentence end => “Edo, Lentes, Javi” Select followers where user_id = 1Friday, August 31, 12
  42. 42. N+1 Queries are not cool def recent_followers self.followers.recent.includes(:user).collect {|f| f.user.name }.to_sentence end => “Edo, Lentes, Javi” Select followers where user_id = 1 Select users where user_id in (2,3,4,5) 2 queriesFriday, August 31, 12
  43. 43. N+1 Queries are not cool def recent_followers self.followers.recent.includes(:user).collect {|f| f.user.name }.to_sentence end => “Edo, Lentes, Javi” Select followers where user_id = 1 Select users where user_id in (2,3,4,5) 2 queries Check out the bullet gem at: h"ps://github.com/flyerhzm/bulletFriday, August 31, 12
  44. 44. Counter cache FTW!Friday, August 31, 12
  45. 45. Counter cache FTW! <%= pluralize @user.tweets.length, tweet %>Friday, August 31, 12
  46. 46. Counter cache FTW! 1. Select all tweets from user <%= pluralize @user.tweets.length, tweet %> 2. Populate an array of objects 3. Call length on the arrayFriday, August 31, 12
  47. 47. Counter cache FTW! 1. Select all tweets from user <%= pluralize @user.tweets.length, tweet %> 2. Populate an array of objects 3. Call length on the arrayFriday, August 31, 12
  48. 48. Counter cache FTW! 1. Select all tweets from user <%= pluralize @user.tweets.length, tweet %> 2. Populate an array of objects 3. Call length on the array <%= pluralize @user.tweets.count, tweet %>Friday, August 31, 12
  49. 49. Counter cache FTW! 1. Select all tweets from user <%= pluralize @user.tweets.length, tweet %> 2. Populate an array of objects 3. Call length on the array <%= pluralize @user.tweets.count, tweet %> 1. Select all tweets from user 2. Do count query for tweetsFriday, August 31, 12
  50. 50. Counter cache FTW! 1. Select all tweets from user <%= pluralize @user.tweets.length, tweet %> 2. Populate an array of objects 3. Call length on the array <%= pluralize @user.tweets.count, tweet %> 1. Select all tweets from user 2. Do count query for tweetsFriday, August 31, 12
  51. 51. Counter cache FTW! 1. Select all tweets from user <%= pluralize @user.tweets.length, tweet %> 2. Populate an array of objects 3. Call length on the array <%= pluralize @user.tweets.count, tweet %> 1. Select all tweets from user 2. Do count query for tweetsFriday, August 31, 12
  52. 52. Counter cache FTW! 1. Select all tweets from user <%= pluralize @user.tweets.length, tweet %> 2. Populate an array of objects 3. Call length on the array <%= pluralize @user.tweets.count, tweet %> 1. Select all tweets from user 2. Do count query for tweets <%= pluralize @user.tweets.size, tweet %>Friday, August 31, 12
  53. 53. Counter cache FTW! 1. Select all tweets from user <%= pluralize @user.tweets.length, tweet %> 2. Populate an array of objects 3. Call length on the array <%= pluralize @user.tweets.count, tweet %> 1. Select all tweets from user 2. Do count query for tweets <%= pluralize @user.tweets.size, tweet %>Friday, August 31, 12
  54. 54. Counter cache FTW! 1. Select all tweets from user <%= pluralize @user.tweets.length, tweet %> 2. Populate an array of objects 3. Call length on the array <%= pluralize @user.tweets.count, tweet %> 1. Select all tweets from user 2. Do count query for tweets <%= pluralize @user.tweets.size, tweet %> 1. Select all tweets from userFriday, August 31, 12
  55. 55. Counter cache FTW! 1. Select all tweets from user <%= pluralize @user.tweets.length, tweet %> 2. Populate an array of objects 3. Call length on the array <%= pluralize @user.tweets.count, tweet %> 1. Select all tweets from user 2. Do count query for tweets <%= pluralize @user.tweets.size, tweet %> 1. Select all tweets from userFriday, August 31, 12
  56. 56. Counter cache FTW! 1. Select all tweets from user <%= pluralize @user.tweets.length, tweet %> 2. Populate an array of objects 3. Call length on the array <%= pluralize @user.tweets.count, tweet %> 1. Select all tweets from user 2. Do count query for tweets <%= pluralize @user.tweets.size, tweet %> 1. Select all tweets from user belongs_to :user, :counter_cache => trueFriday, August 31, 12
  57. 57. Counter cache FTW! 1. Select all tweets from user <%= pluralize @user.tweets.length, tweet %> 2. Populate an array of objects 3. Call length on the array <%= pluralize @user.tweets.count, tweet %> 1. Select all tweets from user 2. Do count query for tweets <%= pluralize @user.tweets.size, tweet %> 1. Select all tweets from user def self.up belongs_to :user, :counter_cache => true add_column :users, :tweets_count, :integer, :default => 0 end def self.down remove_column :users, :tweets_count endFriday, August 31, 12
  58. 58. Rails Best PracticesFriday, August 31, 12
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×