I'm building a ruby on rails app and I have rather big controllers.
Now I have the same actions to be done on a create action and a delete action so I was wandering if it's possible to make this DRY. Or is this only possible with views?
There are a few ways you can achieve this:
Move all model related code to your models and call model actions on models in your controller. This is a great way to clean up your controller especially if you are querying the model for generic things.
Create private actions in your controller to reduce duplication of code.
You can create methods inside a module and import the module into your controller. This should reduce the size of your controller as well as making it DRY (you could even reuse that module in different controllers).
module MyModule
def my_method
end
end
# in controller
include MyModule
You can only create partials in view.
Code repeatation in controller can be made DRY by writing the similar part of code as a method in Model and calling it in as many actions in controller.
In rails4 had a folder which called concern, you can use concern to split your code in controller.
You can refer about concern at: concern
Related
I have functions that return true/false for user permissions (basically a wrapper for certain session variables). I would like the functions available to build menus in the view layer as well within the controllers. Is there any drawbacks in doing this? (Example below)
module SecurityPermissions
extend ActiveSupport::Concern
def has_this_permissions
end
end
class ApplicationController < ActionController::Base
include SecurityPermissions
helper SecurityPermissions
end
Although it is tempting to add everything in the view layer and the controller, it is still recommended that you don't do this. The idea is that the view should not concern about the logic. As much as possible, the view should only render something. Using decorators or page objects will help you abstract these out of your view context.
As for the controller, taking out "action" logic to a service would be my favourite way of simplifying everything. Controllers should not concern about how a model should be updated but it should now what to update.
I have two forms/views which share similar input parameters; but each view is supposed to be processed by a separate controller because additional logic unique to each view is required. Each controller has plenty of input parameters associated with it. What is the best practice?
I know this question may sound like the "Sharing variables between controllers" thing; But if i use the before_filter method; I have to declare every input parameter from the form again. If I define a new method in the parent application controller or create a helper method for input parameter extraction; other methods in the child controller cannot access the variables... Is there a more elegant solution?
I often find cases where I need some reusable business logic outside of a controller. In those cases I'll define a new object in my /lib folder so I can use it multiple places. For example,
# lib/my_business_logic/do_stuff.rb
module MyBusinessLogic
class DoStuff
def self.dostuff(params)
# do stuff
end
end
end
Then I can call:
result = MyBusinessLogic::DoStuff.dostuff(params)
My shopping site has a header that's common across all pages.
I have added a shopping cart icon in the header, with a number that updates based on the contents in the current cart.
Because this icon requires a definition for current_cart, I now need to add this to every controller action. Is this unwise/unsafe? I'm new to rails, and don't quite understand the security repercussions of adding methods to applications.rb
Also, is the best way to do this to add this once to application_controller.rb, or to add it separately to each relevant controller action?
Thanks in advance for the feedback!
Having DRY in mind it's definitely better to add this method once, one level up in yours controller inheritance tree. If all controllers need that method then application_controller.rb is a good place. If just some of them then you may consider to create controller which inherits from ApplicationController, store that method in it, and all controllers that requiers that method should inherits form it.
All of your controllers inherit from the application controller. This means that any method you define in the application controller is available in all of your other controllers.
I've been told that the helpers are just for functions that are needed by the views.
Where should I put in functions that are used commonly by models? What about controllers?
What's the convention to place commonly used functions that will be used in:
1) models
2) views
3) controllers
Problem: Creating a module in lib to hold the functions and including the module in a class would create a boat-load of instance methods for the class.
Problem: What about functions that are common and needed in all three?
Problem: Creating a module in lib to hold the functions and including the module in a class would create a boat-load of instance methods for the class.
First organize, then optimize
Problem: What about functions that are common and needed in all three?
Do you really have methods that are needed in all the three and not exist yet ?
If yes, may be you can give an exemple
I think the question should be where to put logic in general.
You should first think what your method does before to think about where to put it.
But whatever you create, when it's getting big and or valuable, you should really think about exporting it as a gem/plugin.
Inner navigation logic (what to display and where to go after an action) : Controllers
App navigation logic; application_controller
Sub set of app logic; create a namespace with master controller, class API_controller < application_controller
Data logic (How to manipulate, process data) : Models
Data; Model class method (search, sorting, counting, macro process ...)
Datum; Model instance method (modification, micro process ...)
Data presentation logic (How to display data) : Helper, Partial and Decorators
Helper are not designed for that in my opinion.
Partial handle layouting of specific data.
application decorator; handle generic data presentation help
scope_decoration; you can use inheritance
Layout language logic (layout language help) : Helper
Specific to your app; application_helper
Specific to a model ...; model_helper, but you should consider decorator
Generic; export it in a gem (super form helper, templating system ...)
Layout logic (should i display this menu ?) : ?
Helper/decorator/model can should answer the question : #user.can_edit?(#article)
Layout handle the display <%= render :partial => allowed ? "something" : "somthing else" %>
I think if you are not in this configuration you are creating kind of backend system.
So it should go in lib, then in a gem later.
This organization is just an exemple. The most important thing is to organize your code and split different logic layers and don't hesitate to refactor/export code to make it generic after adding new features...
for Controllers - put common methods in application_controller.rb
for Views - put common methods in application_helper.rb
for Models - monkeypatch ActiveRecord::Base to include common methods OR write a module with common model methods and include it in the models that need it OR do it in OOP way by subclassing ActiveRecord::Base with your abstract class, then inheriting all your models from this class.
To use common methods in both Model and Controller, do one of the following:
Write a plain ruby class, put it in /lib or elsewhere, just make sure it's loaded, then require it when you need to use its methods.
Extract common functionality to a gem, install it, require it when you need it. Publish it to rubygems if it's something valuable.
... Usually, I put those kind of functions into common superclasses: For models, that could be (for example) Animal for subclasses Dog, Cat, etc. Within the Animal model, you would have to
self.abstract_class = true
so it doesn't expect a table for that class. For controllers, you could either use ApplicationController or you could make your controllers be derived by another common subclass.
In the Model you should store all the methods that have a relation to the model itself like manipulating attributes, scopes, associating,...
In the View you dont store any logic! The logic belongs to the model. In the view you only put code that helps you to display stuff.
The Controller is the "bridge" between both. You select data in the controller, call methods that are stored in the model,... A common failure is to store the logic in the controller which should be stored in the model.
When you store a method in your Modelyou can access it from the model, the view and the controller! If you have a method that doesn't have a relation to a specific model or its needed in several models you can use the Helper. An example for such a case might be a method that rewrites your url using a pattern. This might be needed in 20 models to prepare a string for to_param. That method would be stored in an Helper that could be included in the Models its needed.
I have some controller methods I'd like to share. What is the best practice for doing this in ruby on rails? Should I create an abstract class that my controllers extend, or should I create module and add it in to each controller? Below are the controller methods I want to share:
def driving_directions
#address_to = params[:address_to]
#address_from = params[:address_from]
#map_center = params[:map_center_start]
# if we were not given a center point to start our map on
# let's create one.
if !#map_center && #address_to
#map_center = GeoKit::Geocoders::MultiGeocoder.geocode(#address_to).ll
elsif !#map_center && #address_from
#map_center = GeoKit::Geocoders::MultiGeocoder.geocode(#address_from).ll
end
end
def printer_friendly
starting_point = params[:starting_point].split(',').collect{|e|e.to_f}
ne = params[:ne].split(',').collect{|e|e.to_f}
sw = params[:sw].split(',').collect{|e|e.to_f}
size = params[:size].split(',').collect{|e|e.to_f}
address = params[:address]
#markers = retrieve_points(ne,sw,size,false)
#map = initialize_map([[sw[0],sw[1]],[ne[0],ne[1]]],[starting_point[0],starting_point[1]],false,#markers,true)
#address_string = address
end
In my opinion, normal OO design principles apply:
If the code is really a set of utilities that doesn't need access to object state, I would consider putting it in a module to be called separately. For instance, if the code is all mapping utilities, create a module Maps, and access the methods like: Maps::driving_directions.
If the code needs state and is used or could be used in every controller, put the code in ApplicationController.
If the code needs state and is used in a subset of all controllers that are closely and logically related (i.e. all about maps) then create a base class (class MapController < ApplicationController) and put the shared code there.
If the code needs state and is used in a subset of all controllers that are not very closely related, put it in a module and include it in necessary controllers.
In your case, the methods need state (params), so the choice depends on the logical relationship between the controllers that need it.
In addition:
Also:
Use partials when possible for repeated code and either place in a common 'partials' directory or include via a specific path.
Stick to a RESTful approach when possible (for methods) and if you find yourself creating a lot of non-RESTful methods consider extracting them to their own controller.
I know this question was asked 6 years ago. Just want to point out that in Rails 4, there're now Controller Concerns that're a more out of the box solution.
I actually think a module is the best way to share code amongst controllers. Helpers are good if you want to share code amongst views. Helpers are basically glorified modules, so if you don't need view level access, I suggest placing a module in your lib folder.
Once you create the module, you'll have to use the include statement to include it in the desired controllers.
http://www.rubyist.net/~slagell/ruby/modules.html
I agree with the module approach. Create a separate Ruby file in your lib directory and put the module in the new file.
The most obvious way would be to add the methods to your ApplicationController, but I am sure you know that already.
if you want to share codes between controller and helpers, then you should try creating a module in library. You can use #template and #controller for accessing method in controller and helper as well.
Check this for more details http://www.shanison.com/?p=305
Another possibility:
If your common code needs state and you want to share the behavior amongst controllers, you could put it in a plain old ruby class in either your model or lib directory. Remember that model classes don't have to be persistent even though all ActiveRecord classes are persistent. In other words, it's acceptable to have transient model classes.
I found that one effective way to share identical code across controllers is to have one controller inherit from the other (where the code lives). I used this approach to share identical methods defined in my controllers with another set of namespaced controllers.