Pragmatic Patterns of Ruby on Rails - Ruby Kaigi2009

11,451 views

Published on

0 Comments
20 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
11,451
On SlideShare
0
From Embeds
0
Number of Embeds
689
Actions
Shares
0
Downloads
95
Comments
0
Likes
20
Embeds 0
No embeds

No notes for slide

Pragmatic Patterns of Ruby on Rails - Ruby Kaigi2009

  1. 1. Pragmatic Patterns of Ruby on Rails Yasuko OHBA( )
  2. 2. what I do • developer of Rails applications • • Everyleaf Corporation
  3. 3. sponsor booth • first time to be a sponsor • we serve candies • you can play ‘Romantic Ruby’ !
  4. 4. my products • home accounting web service http://www.kozuchi.net • http://github.com/everyleaf/kozuchi/ tree
  5. 5. personal message
  6. 6. I started programming when I was 14 years old
  7. 7. school for girls
  8. 8. I was alone
  9. 9. got the job
  10. 10. find similar people
  11. 11. however
  12. 12. ‘enterprise’
  13. 13. only activities inside the company
  14. 14. other things mount up
  15. 15. I was lost
  16. 16. want to write codes
  17. 17. that’s when..
  18. 18. Ruby was given
  19. 19. life becomes happier
  20. 20. Ruby for enterprises
  21. 21. the way to live happily writing codes
  22. 22. And...
  23. 23. great communities
  24. 24. many friends
  25. 25. thank you !!
  26. 26. today’s presentation
  27. 27. coding patterns with Ruby on Rails
  28. 28. the target • large & complicated applications • team
  29. 29. problems of large applications • different coding styles • nasty parts made
  30. 30. becomes harder to maintenance
  31. 31. keep your codes nice
  32. 32. what is the ‘nice code’? • good design • easy to understand • easy to find something wrong
  33. 33. coding patterns work fine • make and share coding patterns • add some DSL (not too much)
  34. 34. efficient, of course
  35. 35. what I won’t say • how to get the best performance • ActiveRecord’s alternatives
  36. 36. ActiveRecord
  37. 37. frankly speaking,
  38. 38. I love ActiveRecord
  39. 39. because
  40. 40. OOP
  41. 41. still able to maintenance when it gets complicated
  42. 42. pragmatic
  43. 43. the heart of RoR
  44. 44. many AR features in this presentation
  45. 45. examples
  46. 46. show permitted data
  47. 47. find starts from an AR object
  48. 48. find a note by id /note/3 def show @note = Note.find(params[:id]) end
  49. 49. find a note of the current user /note/3 @note = Note.find_by_id_and_user_id( params[:id], current_user.id) raise ActiveRecord::RecordNotFound unless @note
  50. 50. /note/3 @note = Note.written_by( curret_user.id).find(params[:id])
  51. 51. hard to notice the luck of condition! @note = Note.find(params[:id]) @note = Note.find_by_id_and_user_id( params[:id], current_user.id) @note = Note.written_by( current_user).find(params[:id])
  52. 52. so,
  53. 53. find starts from an AR object
  54. 54. starts from an object def show @note = current_user.notes.find( params[:id]) end
  55. 55. use the association def show @note = current_user.notes.find( params[:id]) end
  56. 56. association class User < ActiveRecord::Base has_many :notes end
  57. 57. easy to notice problems @note = current_user.notes.find( params[:id]) @note = Note.find(params[:id])
  58. 58. easy to see who can access
  59. 59. who can access @note = current_user.notes.find( params[:id])
  60. 60. filters to find the starting AR object
  61. 61. with the previous pattern
  62. 62. most actions will use the AR object
  63. 63. example; CRUD of the specified group’s notes
  64. 64. • URL • /groups/15/notes • /groups/15/notes/3
  65. 65. • Note has group_id class Note < ActiveRecord::Base belongs_to :group end class Group < ActiveRecord::Base has_many :notes end
  66. 66. def index @group = Group.find(params[:group_id]) @notes = @group.notes.paginate(:page => params[:page]) end def show @group = Group.find(params[:group_id]) @note = @group.notes.find(params[:id]) end
  67. 67. the duplicated line @group = Group.find(params[:group_id])
  68. 68. write that line in a filter
  69. 69. what’s the filter? • the separated logic which would be called around action • declarative
  70. 70. find the group in a filter class GroupNotesController < ApplicationController before_filter :find_group .......actions ...... private def find_group @group = Group.find(params[:group_id]) end end
  71. 71. DRY before_filter :find_group def index @notes = @group.notes.paginate(:page => params[:page]) end def show @note = @group.notes.find(params[:id]) end
  72. 72. easy to change access control
  73. 73. example; change to allow access to members only def find_group @group = current_user.groups.find( params[:group_id] end
  74. 74. other merits
  75. 75. secure
  76. 76. safe if it starts from @group def index @notes = @group.notes.paginate(:page => params[:page]) end def show @note = @group.notes.find(params[:id]) end
  77. 77. filter urges developers to use @group
  78. 78. and
  79. 79. readable
  80. 80. you can understand the controller’s summary from name and filters
  81. 81. understand the summary quickly class GroupNotesController < ApplicationController before_filter :find_group
  82. 82. the points • a good controller name • readable filters
  83. 83. complicated business logics
  84. 84. want to write business logics in models
  85. 85. because
  86. 86. merits of writing business logics in models • easy to test • easy to reuse • readable, easy to find the target codes
  87. 87. however
  88. 88. ‘how’ matters a lot
  89. 89. a bad example class MyModel < ActiveRecord::Base def do_create(params) .... def do_destroy(params) ... end
  90. 90. why is it bad ? • it breaks MVC • hard to reuse
  91. 91. now
  92. 92. let’s move codes from controller to model in good way
  93. 93. move the logic branching on parameters from C to M
  94. 94. branching on parameters def update @note.attributes = params[:note] @tags = params[:auto_tagging] == '1' ? generate_tags(@note) : [] # do saving and tagging ... end
  95. 95. often written in controller
  96. 96. to move to model
  97. 97. add an attribute for branching to the model
  98. 98. the condition params[:auto_tagging] == '1'
  99. 99. as an attribute of the model class Note < ActiveRecord::Base attr_accessor :auto_tagging end
  100. 100. change parameters structure { :note => {.....}, :auto_tagging => '1' } { :note => { ....., :auto_tagging => '1' }}
  101. 101. change the view for it <%= check_box_tag :auto_tagging %> <% form_for :note, ... do |f |%> <%= f.check_box :auto_tagging %> <% end %>
  102. 102. now it’s in params[:note] def update @note.attributes = params[:note] if params[:auto_tagging] == '1' generate_tags(@note) end .....
  103. 103. can branch in the model class Note < ActiveRecord::Base .... if auto_tagging ... end end
  104. 104. finished to move branching
  105. 105. move generate_tags next
  106. 106. move the logic processing other models from C to M
  107. 107. the logic processing other models def update generate_tags(@note) end private def generate_tags(note) tags = Tag.extract(note.body) note.tag_list = tags.join(',') end
  108. 108. also often written in controller
  109. 109. put it into model’s callback class Note < ActiveRecord::Base before_save :generate_taggings private def generate_taggings return unless auto_tagging tags = Tag.extract(body) self.tag_list = tags.join(',') end end
  110. 110. what’s the model’s callback? • methods called before/after save or destroy
  111. 111. Rails Model You normal method call save (validation) before_save do saving after_save
  112. 112. self-directive models
  113. 113. now we’ve done it ! • easy to test • easy to reuse • readable, easy to find the target codes
  114. 114. other patterns • multi levels for validation • design & coding policy for STI • use owner object’s attributes in association • how to make routes.rb a little readable
  115. 115. the last topic
  116. 116. how to find coding patterns
  117. 117. in my case
  118. 118. try to choose the most natural style for RoR
  119. 119. what is the most natural way in Ruby on Rails?
  120. 120. 1. OOP
  121. 121. express business logics as models
  122. 122. always think who should do that job
  123. 123. Note or User ? @note = Note.find_by_id_and_user_id( params[:id], current_user.id) @note = current_user.notes.find( params[:id])
  124. 124. you can’t always decide it from tables
  125. 125. decide it in objects world
  126. 126. 2. follow the principles of RoR
  127. 127. principles of RoR • DRY • CoC • RESTful
  128. 128. accept RESTful in Ruby on Rails
  129. 129. how to design controllers ?
  130. 130. one controller for a type of resources
  131. 131. what’s the resources?
  132. 132. you can find it in URL /companies/everyleaf/notes/3
  133. 133. design of controllers
  134. 134. starts from design of URLs
  135. 135. roughly speaking,
  136. 136. Model Class 1 1..* Resource
  137. 137. the point is...
  138. 138. one controller should provide one resource type’s CRUD
  139. 139. might have been derailed class BlogsController < ApplicationController def create_comment end def comments end def destroy_comment ...
  140. 140. one more
  141. 141. write codes in model’s standard flows
  142. 142. standard flows • find • new → save (create) • find → save (update) • find → destroy
  143. 143. inside of a flow
  144. 144. new attribute = before_ build validation before_ after_ validation save validation creation after_save
  145. 145. write codes in appropriate place
  146. 146. where, what new attribute = before_ build validation before_ after_ validation save validation creation after_save
  147. 147. try to choose the most natural style for RoR
  148. 148. don’t go too far from the basic styles
  149. 149. because
  150. 150. it’s normal to Rails programmers
  151. 151. easy to read for everyone
  152. 152. for that purpose
  153. 153. use Ruby’s flexibility
  154. 154. summary
  155. 155. in developing large & complicated application
  156. 156. it’s important to keep codes nice
  157. 157. for that purpose
  158. 158. be aware of coding patterns, and share them
  159. 159. coding patterns fitting Ruby on Rails
  160. 160. make source codes easy to read for general developers
  161. 161. it means easy to maintain
  162. 162. thank you !

×