Module, helper or something else? - ruby-on-rails

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.

Related

rails coding conventions to improve performance

In my current project, i notice few thing,
Maximum part of the business logic are moved to helper.
Included all helper files in a module under lib directory and included that module in application controller.
In many methods, no argument passed, instead they used the instance variable(create instance variable in calling method and use that instance variable in the called method).
Each action will call a helper method to execute business logic and that method will call some other helper methods.
All method are written as public, No protected and private method.
Models are used only for validation.
are those points follows good coding conventions? if not, can you suggest me the best coding standard to improve performance?
First, convention has nothing to do per se with performance.
Maximum part of the business logic are moved to helper.
I would say this is very bad. One of the popular idioms is "fat models, skinny controllers", which works most of the time. Put all the business logic you can in your models, where they belong. If you have really complicated views you want to simplify, use decorators (e.g the draper gem), and then separate business logic (model) and view logic (decorators) into their according locations.
Included all helper files in a module under lib directory and included that module in application controller.
Okay I think. As long as you have one place to maintain that chain, it feels okay. If it leads to misunderstandings/misusings/hacking around, then: not okay.
In many methods, no argument passed, instead they used the instance variable
If you're talking about methods in your model: this is good, since the method is targeted at the scope of your instance, and not of your class.
Each action will call a helper method to execute business logic and that method will call some other helper methods.
Sounds strange. The controller is responsible for preparing your data used in the view. If you are preparing specific data in your helpers to assign them to your view for usage, consider putting these into a decorator (as mentioned above). But calling a helper in almost every action sounds like something is done the wrong way.
All method are written as public, No protected and private method.
Non-public methods should not be public. Take a look at helper_method and hide_action from ActionController.
Models are used only for validation.
Wrong. Models contain the business logic, as mentioned above. What about modifying things in the console? Would you want to update all logical related data by hand, then? Do you do this "by hand" in your controller right now (which it seems like) ? What about when you introduce an API, do you copy-paste the code in there to not miss some logic? And what when the logic changes, are you really sure all required endpoints manually and independently handling that logic are also updated?
There's a reason models have relations, callbacks and instance methods. Use them!
Performance is not related to your arguments; they are about project organization.
Maximum part of the business logic are moved to helper
This shouldn't happen, you should move the business (aka models) logic inside the models. Rails doesn't force you doing it, so keeping the logic organization is up to developers.
Models are used only for validation
This is a consequence of putting the business (aka models) logic outside the models. You should move it from the controllers/helpers to the models. Again, Rails doesn't force you to do that, so it's up to developers to do it.
Included all helper files in a module under lib directory and included that module in application controller.
In many methods, no argument passed, instead they used the instance variable(create instance variable in calling method and use that instance variable in the called method).
Each action will call a helper method to execute business logic and that method will call some other helper methods.
All method are written as public, No protected and private method.
I think that these points are (some more, some less) related to the Rails Helper design. One flaw of Rails is the Helper design: they go against the OO pattern and usually end up by being a bunch of unorganized functions, à la PHP.
For this reason some people use Decorators. Decorators "add an OO layer of presentation logic" (from Draper), allowing to organize better the view related methods.
If you want to examine the argument, I suggest you the following links:
Google search about decorators
Draper
The Ruby Toolbox, presenters category

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.

Help! My application_helper.rb is getting unwieldily

My application_helper.rb is getting pretty big. In my defense, it contains only HTML-generating methods, and none of those methods perform any sort of business logic. None of the methods are specific to any page or controller, and most are unrelated to each other.
What's the typical solution to this problem? Suck it up? Create additional *_helper.rb files to absorb some of application_helper's methods?
Usually we have helpers for controllers (one helper per controller, were you would place helper methods used only on that controller's templates) and you can also create helpers based on your own organization.
If you have many methods related to polls, you could create a PollsHelper and place all methods in there, even if there isn't a controller called PollsController. Also, Rails always loads all helpers and includes them in your views, so you can name them whatever you like (as long as they're inside the helpers folder and they end with _helper).
Typically I organise by type - e.g. button_and_link_helpers, conditional_helpers etc. I just create them as modules and include them in the controllers that need them.
This has the benefit of not loading loads of unused functions for every view

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

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

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.

Resources