Code shared by multiple controllers and models -- where is the best place to keep it? - ruby-on-rails

So this is a newbie rails design question. Lets say I want some of my common functionality to be sitting in a set of helper classes (either as class methods or instance methods).
And I want to use these helper objects inside controller (not view) or even may be a model. can I do that? how? Does it have to be a module or class or can be anything?
Is there rails specific pattern for this?

If their are not tied to one of the three tiers, you should place them in the /lib directory.
The convention under /lib is that you should name your folders as modules, and files and classes, and that you should always try to encapsulate your additional behavior in modules. Let's say, you have some class
module MyModule
class MyHelperClass
end
end
You should put it into /lib/my_module/my_helper_class.rb

Related

How to use two concerns with the same name?

I want to use concerns app/controllers/concerns/likeable.rb and app/models/concerns/likeable.rb.
The first one goes to controllers and the second one goes to models.
If I create two files, only the first one is loaded.
What's the best way to solve this problem?
I didn't find a way to use controller and model concerns with the same name without any namespaces.
So, my final solution is to use LikeableModel and LikeableController concerns.
I had the same problem but I was able to resolve it by namespacing the controller and model concerns. I moved all model concerns to app/models/concerns/models/ and all controller concerns to app/controllers/concerns/controllers/. With this, it's possible to have model and controller concerns with the same name.
app/models/concerns/models/likeable.rb
module Models::Likeable
end
app/controllers/concerns/controllers/likeable.rb
module Controllers::Likeable
end
The concerns can be included like this;
class Post < ActiveRecord::Base
include Models::Likeable
end
class PostsController < ApplicationController
include Controllers::Likeable
end
Older question, but I thought I'd throw in another option that I believe fits in with Rails conventions a little neater. The Likeable namespace is responsible for dealing with any items that are likeable, and there are controllers that need to deal with building responses for likeable resources, and models for those likeable resources. Both of these can implement aspects of the Likeable concept. What is needed is a breakdown within that namespace of the different responsibilities.
What I would do in this case is create a file in app/controllers/concerns/likeable/respondable.rb that implements the Likeable::Respondable functionality that a Controller provides. (You may find a better name than Respondable for your needs - for instance, if the controller concern only really handles some logic around params, you may call it Likeable::Paramable, etc.)
Similarly, if the model side of your Likeable scaffold has to do mainly with persistence logic, you might define a Likeable::Persistable module in app/models/concerns/likeable/persistable.rb.
In this way, you can still keep all your logic for likeables in a single namespace, and get more specific for your controller and model concerns.
What's nice about this approach is that you can easily add to the namespace later if you find a need for, say, a utility module or class that needs to live in the lib directory for dealing with special calculations or other shared functionality. In that case, you could easily define a Likeable::Utils module in lib/likeable/utils.rb, or something similar depending on the need, and everything will live under that one, consistent namespace.
You can disttingush two concerns with same name using namespace
Following is example
app/controllers/concerns/like/likeable.rb
module Like
class Likeable
# do some stuff here
end
end
app/models/concerns/likeable.rb
class Likeable
# do some stuff here
end

Module, helper or something else?

I've got a bunch of whitelist functions that do some complex validation on parameters. If you must know, I have several controllers that accept either:
A customer ID
e.g. customer=cus_123412341234
A customer Hash
e.g. customer[first_name]=Floating&customer[last_name]=Rock&...
Remember, there are several controllers that do this (e.g. a charge can be created at the charges endpoint using a customer ID or a Hash).
Now I want to know where I should place these methods (e.g. customer_hash_params(),customer_string_params(),..)?
Should I:
Place them in the lib/ folder as a Module
Place them in the helpers/ folder as a Helper
Something else..
Would like to know what the best practice is?
In short, a helper placed into app/helpers might provide some logic for both, controller and view. It is autoloaded for views and need inclusion within controller. A module or class placed within lib folder usually extend some controller or model logic. It is not autoloaded into environment, unless specified within application.rb
As you have some validation logic, that suits for lib directory, because it is not needed within views. I assume these validations are kind of pre-validations and your models do not have all these validated fields defined. Otherwise it would be a good idea to write some custom validators for your models.
Lib Folder in Rails are always used when we have long methods to support controller or model. So that we can call those methods from various controller.
If that is the requirement , Do go for lib Folder, Make a class. Call those class methods in different controllers and models.

Where should I put functions that are accessed by models? -- Rails 3.1

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.

call a helper from another view

I know that if I want to call a helper of another controller, I can do something like:
helper :other_controllers
But I was wondering why I can't do something like OtherControllersHelper.method inside the view?
Due to the way that Rails loads your modules, you cannot do this without modification.
Rails includes the associated helper models into the ActionView::Base instance used to render a template. ActionController::Helpers#helper (used in the example above) adds more helper modules to the list of those to be included. The helper methods that are used in views are written as instance methods. Modules in Ruby do not provide any good ways of getting at instance methods without using a constructor. Which is one of the big things that separates modules from classes.
To access your helpers from another controller with just OtherControllersHelper.method, you will need to redefine method as a class method. However, redefining those methods as class methods would make them inaccessible from your views.
You could duplicate all instance methods in your helpers as class methods, but that's definitely not a better solution that adding helper :other_controllers. There are ways to define wrappers pragmatically, but again, it's not the best way to handle the situation.
If you've got a lot of helpers that are likely to be used in multiple controllers/views maybe you're better off putting them somewhere else. Somewhere like app/helpers/application_helper.rb. Or another helper module that could be loaded only in the controllers that need it.

Best Practices for reusing code between controllers in Ruby on Rails

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.

Resources