Hello everyone! Ive been on rails for the last month or so and really enjoyed this framework. However its very hard to find documentation on how to do things right! For example every beginner after a while realizes that having similar CRUD actions in every controller and views for them is not DRY at all! Few days ago I found http://dereksivers.com/rails-shared-controller.html I quite like his generic controller, not Nub class though ! And I''ve adopted it for my project as: controllers/basic_crud_controller.rb ... class BasicCRUDController < ApplicationController ITEMS_PER_PAGE = 15 before_filter :initialize_crud_controller verify :method => :post, :only => [ :destroy, :create, :update ], :redirect_to => { :action => :list } def index list end def list @items = model_class.find :all, :limit => ITEMS_PER_PAGE, :offset => ITEMS_PER_PAGE * (@sess[:page] - 1) @pages = Paginator.new self, model_class.count, ITEMS_PER_PAGE, @sess[:page] render ''shared/list'' end def new @item = model_class.new #@editform = model_class.editform render ''shared/new'' end def edit @item = model_class.find(params[:id]) #@editform = model_class.editform render ''shared/edit'' end def create @item = model_class.new(params[:edit]) if @item.save #flash[:notice] = ''Region was successfully created.'' flash[:notice] = sprintf(_(:added), _(model_class.table_name.to_sym)) redirect_to :action => :list else #@editform = model_class.editform render ''shared/new'' end end def update @item = model_class.find(params[:id]) if @item.update_attributes(params[:edit]) #flash[:notice] = ''Region was successfully updated.'' flash[:notice] = sprintf(_(:updated), _(model_class.table_name.to_sym)) redirect_to :action => :list #:edit, :id => @region else #@editform = model_class.editform render ''shared/edit'' end end def destroy model_class.find(params[:id]).destroy flash[:notice] = sprintf(_(:deleted), _(model_class.table_name.to_sym)) redirect_to :action => :list end private def initialize_crud_controller id = self.object_id session[id] = { :page => 1 } unless session[id] @sess = session[id] @model_name = model_class.table_name.singularize end end ... By the way, is this a good way to go? Should something like this be generated when you generate scaffold? I believe it should! Then our custom controller looks like this: controller/regions_controller.rb ... class RegionsController < BasicCRUDController def model_class Region end end ... Looks very DRY to me! Now I would like to DRY the views as well Its very easy with list: views/shared/list.rhtml ... <h1>Listing <%= @model_name.pluralize %></h1> <%= link_to ''New '' + @model_name, :action => :new %> <%= link_to ''Previous Page'', { :page => @pages.current.previous } if @pages.current.previous %> <%= pagination_links(@pages) %> <%= link_to ''Next Page'', { :page => @pages.current.next } if @pages.current.next %> <table> <tr> <% for column in controller.model_class.content_columns %> <th><%= column.human_name %></th> <% end %> </tr> <% for item in @items %> <tr class="<%= cycle ''list-line-odd'', ''list-line-even'' %>"> <%= render :partial => ''list'', :locals => { :item => item } %> <td><%= link_to ''Edit'', :action => :edit, :id => item %></td> <td><%= link_to ''Destroy'', { :action => :destroy, :id => item }, :confirm => "Delete #{@model_name}: #{item.name} ?", :post => true %></td> </tr> <% end %> </table> ... And the custom view for list item: views/region/_list.rhtml ... <td><%= item.name %></td> ... Thats looks promising? But there always will be but! The new/edit templates seem not working so far Consider this: views/shared/new.rhtml ... <h1>New <%= @model_name %></h1> <%= start_form_tag :action => :create %> <%= render :partial => ''shared/form'' %> <%= submit_tag ''Create'' %> <%= end_form_tag %> <%= link_to ''Back'', :action => :list %> ... views/shared/_form.rhtml ... <%= error_messages_for @model_name.to_sym %> <!--[form:region]--> <%= render :partial => ''edit'' %> <!--[eoform:region]--> ... views/region/_edit.rhtml ... <p><label for="region_name">Name</label><br/> <%= text_field :region, :name %> </p> ... This way of doing thigs seems to be the right one. So if anyone will get this last bit (new/edit) to work please let me know! I would appreciate any help and suggestions! Thanks! -- Posted via http://www.ruby-forum.com/.
Hi. A few thoughts... It''s okay to "repeat yourself" across multiple controllers. In my mind, controllers should be fairly short. I''ve been where you are -- a lot of controllers look similar, so it''s tempting to combine actions with a little bit of meta magic. But I advise against it. You never know when you''ll need to do something specific in one or more actions. With regards to being DRY... the principle''s core message is that every piece of information in a system should have a single, authorative source or representation. (A hash (dictionary) of real estate terms and the database columns they map to, for example.) The Pragmatic Programmers never intended for you to NEVER repeat yourself. It''s okay to say something twice. Just make sure that when it''s said, it''s acting under the influence of that single source. Cheers, - Daniel -- Posted via http://www.ruby-forum.com/.
Hi Daniel The king of design I was describing above is that what I need right now. Just simple operations with DB and common design. And I believe many other developers are doing the same thing. Besides if I would want something different I always can owerride the DEFAULT behaviour. Isn''t that one of the RoR main principle? Abstraction, metaprogramming, rails, ruby, less code, easy? Anyway its just my opinion. And its not just controllers. The templates are big and cluttered with all sorts of mess. And what if views should look same. Ok. You have 50 different controllers that should look exactly same. This is the main thing! So could you please explain what disadvantaget of this approach you see? Thanks for your thoughts -- Posted via http://www.ruby-forum.com/.
There is nothing wrong with taking this approach Igor if it meets your needs. It is more DRY that way. I think Daniel was just saying that often you need to tweak this or that in the controller methods so you end up overriding a fair amount losing many of the benefits. Also another reason it is used less common is that it might be easier to visualize what is going on in a controller when you see all the methods in one place, much more difficult when split across files. Might not be an issue for you especially if you use mostly the same code everywhere. Justin Ghetland and Stuart Halloway''s Streamlined generator takes this approach currently, so you are not the only one thinking along these lines. I find it to be an interesting idea myself, one which I am going to experiment around with too. It certainly would be more DRY if you don''t have to override that often. Blessings, Jeff Barczewski MasterView Template Engine Developer http://masterview.org/ On 8/4/06, Igor Su <imixaly4@gmail.com> wrote:> Hi Daniel > > The king of design I was describing above is that what I need right now. > Just simple operations with DB and common design. And I believe many > other developers are doing the same thing. Besides if I would want > something different I always can owerride the DEFAULT behaviour. Isn''t > that one of the RoR main principle? Abstraction, metaprogramming, rails, > ruby, less code, easy? > Anyway its just my opinion. > > And its not just controllers. The templates are big and cluttered with > all sorts of mess. And what if views should look same. Ok. You have 50 > different controllers that should look exactly same. This is the main > thing! > > So could you please explain what disadvantaget of this approach you see? > > Thanks for your thoughts > > --
Igor Su wrote:> And its not just controllers. The templates are big and cluttered with > all sorts of mess. And what if views should look same. Ok. You have 50 > different controllers that should look exactly same. This is the main > thing!If you feel combining controllers and views makes sense then do it. Igor Su wrote:> So could you please explain what disadvantaget of this approach you see?Like Jeff said, I think the primary disadvantage is a lack of flexibility. I''ll also say it doesn''t scale well. I''m working with 5 major models, all of which have very similar functionality (setting schedules, selling services) and tried dearly to get everything to work in one set of controllers. At the time it made sense. SchedulesController should handle schedules for everything! Well, after about two weeks, I realized it wasn''t working. There were too many idiosyncracies within each of the five models that the controller was quickly becoming ugly and unwieldly. I''m a fan of context over consistency. Code in a manner that makes sense for your situation. (I might add, your situation _right now_. Don''t get too caught up in designing for ages to come.) - Daniel -- Posted via http://www.ruby-forum.com/.