John Merlino
2013-Apr-02 21:54 UTC
invoking helper method in controller and view breaks the separation of concern?
I came across some posts which postulate that it''s undesirable to share helper methods across controller and views because UI code (designed to render HTML) should be separate from controller code (designed for handling requests). That makes sense but there are times, a good example is filtering, when it only makes sense to create a reusable method to query against the params hash from both controller and view. For example, I created some custom filtering and sorting. When a http request is initially made, my controller must be able to query the database for results without user input. # controller layer (query a default without user input) helper_method :sort_column, :sort_direction, :for_selected_month, :for_selected_year def driver_reports_table @drivers = Driver.select("drivers.*, #{sort_column}").joins([:reports, :driving_habits]).by_month(for_selected_month.to_i, for_selected_year.to_i).order(sort_column + " " + sort_direction).page(params[:page]).per(10) @unit = current_unit respond_to do |format| format.html { render :partial => ''/home/reports/ driver_reports_table'', :layout => false, :locals => { :drivers => @drivers, :unit => @unit } } format.json { render :json => @drivers} end end private def sort_column if legal_attributes.include? params[:order] params[:order] else "drivers.id" end end def sort_direction %w[asc desc].include?(params[:direction]) ? params[:direction] : "asc" end def for_selected_month (params[:date] && params[:date][:month]) || Time.now.month end def for_selected_year (params[:date] && params[:date][:year]) || Time.now.year end def legal_attributes @columns ||= Driver.column_names + DrivingHabit.column_names end In my view layer, the user will interact with form elements and links to modify the values of the params hash In one situation, I have a form tag where the user will set the date and date and month/year attributes of the params hash: #view = form_tag driver_reports_path, :method => ''get'', :id => ''drivers_filter'' do %fieldset.filter_tab = select_month(Date.today) = select_year(Date.today, :start_year => 2012, :end_year => Time.now.year) = submit_tag "Filter Date" = render ''/home/reports/driver_reports_table'' In another situation, I have links where the user will set the sort and direction attributes of the params hash, depending on which link they click: #partial = hidden_field_tag :sort, params[:sort] = hidden_field_tag :direction, params[:direction] ... %table.sortable %tr = sortable "id", :order => "drivers.id" #helper def sortable(column, query_string={}) title ||= column.titleize query_string[:order] = query_string[:order] || column css_class = ''driver_refresh'' css_class << (column =sort_column.gsub("driving_habits.","").gsub("drivers.","") ? " current #{sort_direction}" : "") query_string[:direction] = column =sort_column.gsub("driving_habits.","").gsub("drivers.","") && sort_direction == "asc" ? "desc" : "asc" query_string[:page] = nil content_tag :th, link_to(title, driver_reports_path(params.merge(query_string)), {:class => css_class }) end Each of the situations compensate for the other. If the user selects an option from the select tag and thus populates the date attributes, when they click a link, it will merge the date attributes from the form with the link attributes that were selected and thus send them together to the server. Conversely, when the form is submitted, because of the hidden field tags with the current value of the sort and direction attributes stored in them, those attributes will be send with the form attributes. As you can see, my view helper makes use of the sort_column and sort_direction methods to check the current values in the params hash to determine how to render the links. So those methods have importance both in the controller and view layer. So it would make sense to define the methods once and reuse them in both layers. So what is wrong with this technique and how else could it be done so as not to violate the MVC structure and separation of concerns? -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit https://groups.google.com/groups/opt_out.
tamouse mailing lists
2013-Apr-03 23:37 UTC
Re: invoking helper method in controller and view breaks the separation of concern?
I am unfamiliar with this concept of separating helper functions. In the interest of DRY code, what you''re doing makes complete sense to me. On Tue, Apr 2, 2013 at 4:54 PM, John Merlino <stoicism1-YDxpq3io04c@public.gmane.org> wrote:> I came across some posts which postulate that it''s undesirable to > share helper methods across controller and views because UI code > (designed to render HTML) should be separate from controller code > (designed for handling requests). That makes sense but there are > times, a good example is filtering, when it only makes sense to create > a reusable method to query against the params hash from both > controller and view. For example, I created some custom filtering and > sorting. When a http request is initially made, my controller must be > able to query the database for results without user input. > > > # controller layer (query a default without user input) > helper_method :sort_column, :sort_direction, :for_selected_month, :for_selected_year > def driver_reports_table > @drivers = Driver.select("drivers.*, > #{sort_column}").joins([:reports, :driving_habits]).by_month(for_selected_month.to_i, > for_selected_year.to_i).order(sort_column + " " + > sort_direction).page(params[:page]).per(10) > @unit = current_unit > respond_to do |format| > format.html { render :partial => ''/home/reports/ > driver_reports_table'', :layout => false, :locals => { :drivers => > @drivers, :unit => @unit } } > format.json { render :json => @drivers} > end > end > > > private > > def sort_column > if legal_attributes.include? params[:order] > params[:order] > else > "drivers.id" > end > end > > def sort_direction > %w[asc desc].include?(params[:direction]) ? params[:direction] : > "asc" > end > > def for_selected_month > (params[:date] && params[:date][:month]) || Time.now.month > end > > def for_selected_year > (params[:date] && params[:date][:year]) || Time.now.year > end > > def legal_attributes > @columns ||= Driver.column_names + DrivingHabit.column_names > end > > In my view layer, the user will interact with form elements and links > to modify the values of the params hash > In one situation, I have a form tag where the user will set the date > and date and month/year attributes of the params hash: > #view > = form_tag driver_reports_path, :method => ''get'', :id => > ''drivers_filter'' do > %fieldset.filter_tab > = select_month(Date.today) > = select_year(Date.today, :start_year => 2012, :end_year => > Time.now.year) > = submit_tag "Filter Date" > = render ''/home/reports/driver_reports_table'' > > In another situation, I have links where the user will set the sort > and direction attributes of the params hash, depending on which link > they click: > #partial > = hidden_field_tag :sort, params[:sort] > = hidden_field_tag :direction, params[:direction] > ... > %table.sortable > %tr > = sortable "id", :order => "drivers.id" > > #helper > def sortable(column, query_string={}) > title ||= column.titleize > query_string[:order] = query_string[:order] || column > css_class = ''driver_refresh'' > css_class << (column => sort_column.gsub("driving_habits.","").gsub("drivers.","") ? " current > #{sort_direction}" : "") > query_string[:direction] = column => sort_column.gsub("driving_habits.","").gsub("drivers.","") && > sort_direction == "asc" ? "desc" : "asc" > query_string[:page] = nil > > content_tag :th, link_to(title, > driver_reports_path(params.merge(query_string)), {:class => > css_class }) > end > > Each of the situations compensate for the other. If the user selects > an option from the select tag and thus populates the date attributes, > when they click a link, it will merge the date attributes from the > form with the link attributes that were selected and thus send them > together to the server. Conversely, when the form is submitted, > because of the hidden field tags with the current value of the sort > and direction attributes stored in them, those attributes will be send > with the form attributes. > > As you can see, my view helper makes use of the sort_column and > sort_direction methods to check the current values in the params hash > to determine how to render the links. So those methods have importance > both in the controller and view layer. So it would make sense to > define the methods once and reuse them in both layers. So what is > wrong with this technique and how else could it be done so as not to > violate the MVC structure and separation of concerns? > > -- > You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. > To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org > To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org > For more options, visit https://groups.google.com/groups/opt_out. > >-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit https://groups.google.com/groups/opt_out.
Robert Walker
2013-Apr-03 23:46 UTC
Re: invoking helper method in controller and view breaks the separation of concern?
John Merlino wrote in post #1104251:> As you can see, my view helper makes use of the sort_column and > sort_direction methods to check the current values in the params hash > to determine how to render the links. So those methods have importance > both in the controller and view layer. So it would make sense to > define the methods once and reuse them in both layers. So what is > wrong with this technique and how else could it be done so as not to > violate the MVC structure and separation of concerns?First a disclaimer... Everything I''m about to say is an opinion, nothing more, nothing less. As a developer who has worked with a number of MVC frameworks I really don''t consider Rails to be a very "pure" MVC. Views and controllers are more tightly coupled to each other than in other MVC systems I''ve worked with. Take the simple example that controller instance variable are "made available" in views. That''s a lot of knowledge that the view has about the controller, where in a "pure" MVC environment a view would know nothing about the internal implementation of a controller. For example, a text field in a desktop style application is a "pure" view object. It has zero knowledge about the controller that interact with it nor the model where the controller gets the data. That text field can be used in any context, anywhere, in any application without modification. Compare that to something like: form_for @product This is obviously a view component (a form) yet is has direct knowledge of what type of object it gets it''s data from (an instance of a Product). The product is provided to the view template by the controller through a form of "injection," but having this direct dependency ties the view to working with a specific type of model object that is provided by a specific controller instance. My point is not to start a war around the definition of MVC. I''m just saying that MVC is a guideline pattern. If you have a solution that works well for your application then feel free to use it. -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit https://groups.google.com/groups/opt_out.
Julian Leviston
2013-Apr-03 23:55 UTC
Re: Re: invoking helper method in controller and view breaks the separation of concern?
On 04/04/2013, at 10:46 AM, Robert Walker <lists-fsXkhYbjdPsEEoCn2XhGlw@public.gmane.org> wrote:> As a developer who has worked with a number of MVC frameworks I really > don''t consider Rails to be a very "pure" MVC. Views and controllers are > more tightly coupled to each other than in other MVC systems I''ve worked > with.I''m interested in which ones you do think adhere to pure MVC? What''s the golden example? WebObjects? I''m just interested. :) Julian -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit https://groups.google.com/groups/opt_out.