Should I prevent making I18n translation calls in models - ruby-on-rails

This is a question merely about code style.
I am working on a multilingual app in Ruby on Rails 4. My personal feeling tells me ideally to not do calls to I18n.t() in models, I just think model methods should be consistent, and not depending on varying environmental situations like the current user's locale, especially since I18n is usually related to views. I've got a few questions about this though:
Do you think this is a good rule in general?
How should I manage error messages in custom validation methods? Should I make exceptions for that scenario?
How should I manage customised keys that we use in form fields, such as the displayed text of a collection_select, that are partially translated? Is there a way to use view helpers for these occasions, that is (almost) as convenient as building model methods for these?

Yes. Translations belong to the view layer and only to the "display" part of it (that is, not to the API, which is still view)
Error messsages should be standard enough so you get to translate them correctly by iterating them in the view and getting the piecewise translations. Unfortunately that's not always possible because of different grammatical order of the sentences in languages. Still it's not useful to move those translations to the model. ActiveRecord's Errors class has hooks for translations just like ActiveModel, so the view can rely on them without injecting any i18n in the model itself.
Select helpers can often take a lambda as a label generator, you can use and abuse view paths and relative i18n keys and whatever you need without having to inject anything in the model. In case of doubt, use a presenter and inject I18n in it.

Related

Spreadsheet-like way to add records to ActiveAdmin

I am looking for a way to add a lot of records at ones in ActiveAdmin. To be more specific, I have 2 models: Stores and Programs. Stores have many Programs.
I don't mind adding a Store using standard ActiveAdmin create view. But I would like a faster way to add programs in a spreadsheet-like way. I looked into best_in_place (https://github.com/bernat/best_in_place) but it doesn't do do adding records, just editing them.
Any suggestions? I would really appreciate it.
The short answer is Rails has nothing to help you do this. Rails has a defined convention for editing multiple objects if they belong to another object that can accept nested attributes for a few reasons, the most important of which is that there's a place to aggregate validation, as well as a standard way to differentiate each set of fields (the id). Neither of these are true during creation.
You can, however, manually work around this a couple of ways.
would be to simply write out the forms yourself, and put the logic to loop through them in your controller. This is going to be fragile, and you'll have issues getting validation to work properly, however.
would be to either create a new class that handles this single case, or try and adapt your existing Store class to handle nested attributes. There's a very solid explanation of how to do this here.

Implementing a multi-parameter search service

I would like to design a search service which applies to a multiple set of different request paramaters. It could be called with one parameter only, or with more.
The problem is that some of the params could only be used solely, or are mutually exclusive with others.
Another problem is that some params are really required, while others are only optional.
The easiest way to resolve this is to involve a series of if-statements in the controller's search method, checking for the existence of some parameters or sets of parameters, and reacting correspondingly. Coming from the world of Java however, I have been taught to disbelieve anything that ends up in a bunch of if or switch statements. Back there, we often resort to factories, to which we delegate the decision to choose a proper search strategy from a bunch of strategy classes. All that was ever necessary, was to configure a proper mapping between request parameters and strategy classes.
I also know that the Rails dev mentality tends to solve about problem in a much less abstract and more business-like manner.
What is the proper way to make complex multi-parameter search service?
Rails 2: searchlogic
Rails 3: meta_search
Then it's as easy as Model.search(params[:search])
Sleep easy.

A way to handle common behaviors

I am using Ruby on Rails 3.0.7 and I have multiple resources that almost have the same behavior. That is, those almost have same model, controller and view codes and same database table columns definition.
So I would like to find a way to DRY those resources. I already implemented modules and mixins for those in order to share part of the code (as validation methods, callbacks, view files but not controller files that, anyway, have very similar code).
Now, how can I do to handle this common behavior? Should I use something that Ruby on Rails developers named as acts_as_something? What do you advice about?
I think you already did that, just name a method in your modules act_as_your_module_name and make sure your module extends from your Base Class, e.g. ActiveRecord::Base.extend act_as_your_module_name
http://www.cowboycoded.com/tag/acts_as/

Helpers in rails

I'm just starting out in Rails and there's a lot I still need to learn so I'm likely to be on Stackoverflow more often than normal asking beginner Rails / Ruby questions.
I'm just trying to figure out how Helpers work in Rails. From what I've seen so far, Helpers are intended to be used with Views and not so much with your Controllers.
However I would like to make a simple function that will validate the user input given in params (check if certain params are defined and optionally check if their value is valid).
Can anyone explain to me what would be the best way of implementing this? (Keeping in mind that I will want to use this in many different controllers so it should be globally available.)
I also noticed that by default Rails does not generate a lib folder in the main application folder. Are developers to place their libs outside the app folder in the main folder, or does Rails use libraries differently?
With regards to your validation issue, it depends on what you are validating.
If the data makes up objects from your problem domain, also known as models, then you should use the built in validators from ActiveModel. This is probably what you should do, but its hard to say without knowing the exact problem. See the Rails Guides on Validations. You can tell if this is the case by asking yourself if the data that needs validation will be stored after you get it. If so, its most definitely a model. An example of this kind of data would be the title and text fields of a blog post being sent to Rails from a browser form.
If the data is something tertiary to your models, or specific to presentation, then you should be fine using helpers. You noticed that helpers are used mostly in the views, and although this is true, theres nothing stopping you from using them in the controllers, you just have to declare that you will use them using the ActiveController#helper method. Inside the ApplicationController class, a lot of devs will put helper :all to just include all the helpers in all the controllers. Once the code has been required once, it doesn't really incur that big a performance hit.
Do note that almost all incoming data can be modeled using a model. A big school of thought in the Rails world subscribes to the Fat Model idea. People say that putting as much code as possible in the model and as little in the controller as possible separates concerns properly and leads to more maintainable code. This suggests that even if you don't think the incoming data is modelable (in the sense that you can create a model to represent it), you should try to make it a model and encapsulate the logic around validating it. However, you may find that making a helper function is faster, and either will work.
Your notion of validating user input is a good one. I get the feeling that as you are new to Rails you are used to doing these things yourself, but that doesn't quite apply here. In the Rails world, a lot of the common stuff like validations is handled by the framework. You don't have to check for presence in the params array, instead you call validates_presence_of on the model and let Rails spit the error out to the user. It makes things easier in the long run if you let the framework do what it is designed to.
With regards to your question about the lib folder, it doesn't really matter. You can put miscellaneous support files and libraries in the lib folder in the root directory and they will be available for use in your application (the files in the app folder). You can also choose to abstract your code into a plugin or a gem and include it that way, which a lot of people opt to do. My suggestion for this would be to read up on the notion of gems and plugins before diving in.
Want you want is probably a custom validator (in Rails3):
http://railscasts.com/episodes/211-validations-in-rails-3
You can either add libs in a lib folder you create, or add them to config/initializers in a file you add. Files in the initializers directory are automatically loaded by Rails.

Correct way to optimize repeated Rails code

I have a Rails application with several models-views-controllers which have some similar characteristics, for example 5 different models can be commented on, voted on or tagged, I am also heavily using external plugins.
At the moment I introduced comments, votes, tags, etc. only to a single model (and its view and controller). However, now that I am happy with the results, I want to cut out this common functionality from the particular MVC of one model and allow access to it from all other models.
Some questions before I start doing this (and maybe some general advice will also be great):
1 - How should I go about it? I was thinking creating a module in "lib" directory (is it the same as mixin class?) and then moving reusable view code to common partials. What about the controller code?
2 - As I was just learning Ruby on Rails during the coding of the first model, I went with a probably incorrect way of adding a bunch of methods to the controller. I have a method that adds a comment (addcomment), adds a vote (addvote), etc. All these methods require non-standard (non-RESTful) routing via :collection. From what I understand, the correct way would be to move comments controller functionality to its own controller and access via standard RESTful routes. Is this what I should be doing?
3 - Many plugins (eg. act_as_commentable) do not explicitly require loading a Module, just a line "act_as_commentable" somewhere in the Model. Can I use something like this for my common functionality? How does it work?
A simple way is to split the code into modules and use mixin.
A better way is to write your own plugins for your common code.. like act_as_commentable
you can learn about it here: http://guides.rubyonrails.org/plugins.html
The correct way is to do a comments controller, and have it nested to your models, giving a restful routes like this: /mymodelname/1/comments.
An easy way to make such controllers is by using inherited_resources plugin.
scroll down to the "Polymorphic belongs to" section- there is a comments controller example
For repeated model code, put it in a module in the lib directory.
For controller code, put your duplicate code in ApplicationController.
For your view code, use partials.

Resources