Upgrade to Pro — share decks privately, control downloads, hide ads and more …

OOP in Rails applications

OOP in Rails applications

Talk held on March 7, 2012, at Krakow Ruby User Group. It presents some of the OOP concepts introduced in the book 'Objects on Rails' by Avdi Grimm.

Mariusz Lusiak

March 12, 2012
Tweet

More Decks by Mariusz Lusiak

Other Decks in Programming

Transcript

  1. Plan of action Intro Exhibits Passing methods around ActiveRecord as

    implementation detail Extracting a role from a model
  2. 1 <!-- app/views/blog/_entry.html.erb --> 2 <% if entry.image_url.present? %> 3

    <%= render "/posts/picture_body", post: entry %> 4 <% else %> 5 <%= render "/posts/text_body", post: entry %> 6 <% end %>
  3. 1 # app/exhibits/picture_post_exhibit.rb 2 require 'delegate' 3 class PicturePostExhibit <

    Exhibit 4 def render_body(context) 5 context.render(partial: "/posts/ picture_body", locals: {post: self}) 6 end 7 end
  4. 1 class PostsController < ApplicationController 2 def show 3 @post

    = exhibit(Post.find_by_id(params[:id]), self) 4 respond_with(@post) 5 end 6 end
  5. Exhibit characteristic Wraps a single model instance Is a true

    Decorator Brings together a model and a context
  6. Exhibit characteristic Wraps a single model instance Is a true

    Decorator Brings together a model and a context Encapsulates decisions about how to render an object
  7. Exhibit characteristic Wraps a single model instance Is a true

    Decorator Brings together a model and a context Encapsulates decisions about how to render an object May modify the behaviour of an object
  8. 1 class Blog 2 attr_writer :post_source 3 4 private 5

    6 def post_source 7 @post_source ||= Post.public_method(:new) 8 end 9 end
  9. 1 class Post < ActiveRecord::Base 2 include FigLeaf 3 hide

    ActiveRecord::Base, ancestors: true, 4 except: [Object, :init_with, :new_record?, 5 :errors, :valid?, :save] 6 hide_singletons ActiveRecord::Calculations, 7 ActiveRecord::FinderMethods, 8 ActiveRecord::Relation 9 # ...
  10. 1 module TaggableRecord 2 def tags 3 _tag_list 4 end

    5 6 def tags=(new_tags) 7 @_tag_list = TagList.new(new_tags) 8 end 9 10 # ... 11 end
  11. 1 module TaggableRelation 2 def all_tags_alphabetical 3 all_tags.alphabetical 4 end

    5 6 def all_tags 7 except(:limit).map{|e| Taggable(e).tags}.reduce(TagList.new([]), &:+) 8 end 9 10 def tagged(tag) 11 select{|e| Taggable(e).tags.include?(tag)} 12 end 13 end
  12. 1 def Taggable(item) 2 case item 3 when ::Class, ::ActiveRecord::Relation

    4 item.extend(::TaggableRelation) 5 else 6 item.extend(::TaggableRecord) 7 end 8 end
  13. 1 def create 2 @post = Taggable(@blog.new_post(params[:post])) 3 if @post.publish

    4 redirect_to root_path, notice: "Post added!" 5 else 6 render "new" 7 end 8 end
  14. 1 class PostExhibit < Exhibit 2 # ... 3 def

    tags 4 exhibit(Taggable(to_model).tags) 5 end 6 # ... 7 end
  15. 1 def tagged(tag) 2 joins("JOIN item_tags ON item_tags.item_id = #{table_name}.id

    AND " \ 3 "item_tags.item_type = \"#{klass.name}\""). 4 joins("JOIN tags ON item_tags.tag_id = tags.id"). 5 where("tags.name = ?", tag) 6 end