56293

Is it bad to have fat views in rails?

Question:

I have a RESTful controller that is responsible for building many different models. This means that any given view would requires a handful of variables to be set before it can be rendered correctly. If I set those variables in the controller, then the code would have to be duplicated across different actions that might render that view. For example, rendering Page 1 requires 5 variables. If show, create, and update all render that view, then the code to set those 5 variables is duplicated across those controller actions. The alternative is to just put all of that code inside the view. But that can get really ugly:

<% variable1 = Model1.where(some conditions) %> <% variable2 = Model2.where(some other conditions) %> <% variable3 = Model3.where(some third conditions) %>

I'm hesitant about this solution because of how much code goes into the views. I've always followed the principle that the code in views shouldn't touch the database. Another method I'm entertaining is creating private methods that focus on setting variables and rendering a view. This method could be called by all the actions that require rendering.

Answer1:

In my point of view, all your logic should be placed in your controller, models, helpers or libraries. In your case, setting variables should be done in your controller and not in your views.

It's really interresting to place your logic at the good place, because it will be more easy to debug, maintain or refactore your application if your code is at the good place.

So, here are some ideas to put your variables declarations in your controller without duplicate your code :)

<h2>before_action (in controller)</h2>

You can use before_action in your controller. It will reduce the duplicated code.

For example, you can do:

before_action :set_variables def set_variables @var1 = some_code @var2 = other_code ... end

You can restrict the before_action to only specific actions by using only or except

before_action :set_variables, only: [:index, :edit]

This will call set_variables only before index and edit

<h2>before_action (in application_controller.rb)</h2>

If you want to add a before_action for all index actions in every controllers for examples, you just have to do a before_action in your application_controller.rb

And if you want to skip this type of before_action in a specific controller, you can use the skip_before_action method.

# application_controller.rb before_action :set_variables, only: :index # specific_controller.rb skip_before_action :set_variables <h2>One more thing: model scopes</h2>

Then, a last thing before the end: Model1.where(some conditions). What about model scopes?

Your code will be more readable and less duplicated:

class MyModel < ActiveRecord::Base scope :active, -> { where(is_active: true) } end MyModel.active # equivalent to MyModel.where(is_active: true)

Answer2:

You can add private methods to your controllers and call them within your action methods:

class MyController < ApplicationController # snip ... def my_action @variable1 = get_variable1() @variable2 = get_variable2() @variable3 = get_variable3() @action_specific_variable = Model4.where(my_condition) end def my_other_action @variable1 = get_variable1() @variable2 = get_variable2() @variable3 = get_variable3() @action_specific_variable = Model5.where(my_other_condition) end private def get_variable1() return Model1.where(some conditions) end def get_variable2() return Model2.where(some other conditions) end def get_variable3() return Model3.where(some third conditions) end end

If you need the logic to get these variables to be available across controllers, create a new utility module in you lib folder. For example, you might make a file lib/utilities.rb that contains

module Utilities def self.get_variable1() return Model1.where(some conditions) end def self.get_variable2() return Model2.where(some other conditions) end def self.get_variable3() return Model3.where(some third conditions) end end

and then your controller would look like

class MyController < ApplicationController # snip ... def my_action @variable1 = Utilities::get_variable1() @variable2 = Utilities::get_variable2() @variable3 = Utilities::get_variable3() @action_specific_variable = Model4.where(my_condition) end def my_other_action @variable1 = Utilities::get_variable1() @variable2 = Utilities::get_variable2() @variable3 = Utilities::get_variable3() @action_specific_variable = Model5.where(my_other_condition) end end

Answer3:

If you're looking for a way to associate complex logic with a particular view so that the logic is executed every time that view is created, even if it's generated with methods that don't exist yet, you can use Rails helpers. Every controller has a helper associated with it. For example, if you have a file app/controllers/my_controller.rb, Rails will automatically look for a file called app/helpers/my_helper.rb.

Any methods defined in a helper are available to views that are created by the associated controller. So, for example, let's say you have this controller:

def MyController < ApplicationController # snip ... def my_action @var = "some value" end end

and a view app/views/my/my_action.html.erb:

<% variable1 = Model1.where(some conditions) %> <% variable2 = Model2.where(some other conditions) %> <% variable3 = Model3.where(some third conditions) %> <%= "#{variable1} #{variable2} #{variable3} #{@var} %>

You can refactor the code that accesses the models into app/helpers/my_helper.rb:

module MyHelper def get_variable1() return Model1.where(some conditions) end def get_variable2() return Model2.where(some other conditions) end def get_variable3() return Model3.where(some third conditions) end end

And refactor your view like this:

<% variable1 = get_variable1() %> <% variable2 = get_variable2() %> <% variable3 = get_variable3() %> <%= "#{variable1} #{variable2} #{variable3} #{@var} %>

Without having to modify your controller.

Recommend

  • undefined method `render' for class `ActionView::Base'
  • named parameters in sp_executesql
  • include dlls in visual studio c++ 2008
  • Opaque reference instead of PImpl. Is it possible?
  • react split panel resize
  • Can you pass an array from javascript to asp.net mvc controller action without using a form?
  • Mixing WebForms and MVC: What should I do with the MasterPage?
  • How to create CGPath from a SKSpriteNode in SWIFT
  • Jquery popup on mouse over of calendar control
  • RxJava debounce by arbitrary value
  • Z3: Convert between FP and BitVector?
  • Using a canvas object in a thread to do simple animations - Java
  • uniform generation of points on 3D box
  • What does 'Language neutral' mean with regard to MAKELANGID?
  • Visual Studio 2010 debugger build correctly - compiler pdb and linker pdb not in synch?
  • onBackPressed() not being executed
  • WPF - CanExecute dosn't fire when raising Commands from a UserControl
  • How do I get HTML corresponding to current DOM tree?
  • How to use carriage return with multiple line?
  • How to use remove-erase idiom for removing empty vectors in a vector?
  • How to create a file in java without a extension
  • Highlight one bar in a series in highcharts?
  • Android screen density dpi vs ppi
  • Getting last autonumber in access
  • C# - Serializing and deserializing static member
  • How would I use PHP exceptions to define a redirect?
  • Incrementing object id automatically JS constructor (static method and variable)
  • How to extract text from Word files using C#?
  • ActionScript 2 vs ActionScript 3 performance
  • How to make Safari send if-modified-since header?
  • Weird JavaScript statement, what does it mean?
  • Timeout for blocking function call, i.e., how to stop waiting for user input after X seconds?
  • Do create extension work in single-user mode in postgres?
  • How to pass list parameters for each object using Spring MVC?
  • -fvisibility=hidden not passed by compiler for Debug builds
  • Why joiner is not used after Sequence generator or Update statergy
  • How to CLICK on IE download dialog box i.e.(Open, Save, Save As…)
  • Setting background image for body element in xhtml (for different monitors and resolutions)
  • need help with bizarre java.net.HttpURLConnection behavior
  • JaxB to read class hierarchy