I have some very big models that I must migrate to the latest version of Rails. These models have quite a bunch of validations(User has aprox. 50 validations).
Is it possible to move all these validations in another file? Say app/models/validations/user_validations.rb. And if it is can someone provide an example, please?
You can use concerns for this:
# app/models/validations/user_validations.rb
require 'active_support/concern'
module UserValidations
extend ActiveSupport::Concern
included do
validates :password, presence: true
end
end
# app/models/user.rb
class User
include UserValidations
end
You may need/want to namespace your concerns depending on your autoload path configuration:
# app/models/validations/user.rb
require 'active_support/concern'
module Validations
module User
...
# app/models/user.rb
class User
include Validations::User
From a style perspective you may want to think about why you have so many validations. Shunting them into a module will slim down the model file, but effectively the class still carries all that code around with it. you're effectively sweeping the problem under the carpet.
Are you using a lot of different forms with different validation requirements? If so, you can use form objects (which include ActiveModel functionality) to encapsulate the validations and processing needed for each form, taking the strain off the models.
Do your models have an insane number of fields? Maybe your user object needs to be composed from smaller objects like a profile, address, avatar, etc.
Of course, this is outside the scope of a version migration!
If you can't or don't want to use ActiveRecord concerns (which have some dependency management code that you may not want to carry around), you can use the excellent and tiny plug-in 'augmentations' or the derived gem:
https://github.com/chemica/augmentations-gem
This uses a very similar syntax and far less code. It also doesn't use the term 'concerns', which can mean something else in the OO terminology for different languages/frameworks.
Related
Trying to perform RemoteAuthetication with devise, i ran into an example (almost an official one, since devise wiki is limited to refer to this document).
All the classes that actually implement the authentication algorithm are "double" enclosed into either Devise, Models or Devise, Strategies.
Here is the Devise, Models example:
module Devise
module Models
module RemoteAuthenticatable
extend ActiveSupport::Concern
def remote_authentication(authentication_hash)
# Your logic to authenticate with the external webservice
end
end
end
end
First question: how can you explain to a ruby newbie (as I am), maybe coming from another language, such as java, what is the rationale of this sort of namespace?
While namespaces in different flavours are common among programming languages, this particular way of using them is somewhat new to me.
In other languages one wouldn't use the very same namespace of the thirdy party library (such as devise in this case) even when implementing interfaces or extending classes provided by it.
But here we see that devise itself, in its bits, defines a
module Devise
module Models
module Authenticatable
extend ActiveSupport::Concern
...
end
end
Second question: here the module Authenticatable seems to extend another module. I found lots of docs about classes including or extending other modules, but not modules extending other modules. What is the purpose of this?
Re: Question 1
The namespacing provides organization. Devise is made up of a few parts that integrate into your application eg. Models, Controllers, Authentication logic, etc...
The reason one would use the same namespacing can be
to keep that same organizational structure.
to add/edit the original modules and/or classes. Ruby allows one to reopen a class or module and override or add additional logic. So one doesn't have to extend/include a class/module to patch in there own code.
However, you do want to take care when reopening a class/module you don't own.
Re: Question 2
Modules are very similar to Class (Class actually is a child of Module, which then goes up the chain to Object then BasicObject), with the exception they can't be Instantiated. But, they can have methods, variables and all that jazz and act as a singular object. So modules can naturally include and extend other modules to gain the logic to use within the module that is doing the including or extending.
Ruby Class Docs,
Ruby Module Docs
If you look at the object model, Ruby modules get appended to the ancestors chain in classes. So:
Module B; end
class A
include B
end
A.ancestors # => A, B, etc.
Now when B extends another module:
Module C
def a_module_method; end
end
Module B; extend C; end
Then Ruby adds a_module_method to the class methods in the ancestors chain. So you can do:
A.a_module_method
So it is a different way to give you access to module methods. A good rationale for this is to isolate instance methods from class methods.
I was just wondering what the recommended approach would be for validating a form that is not based on a model. I agree that generally all validation should be done in models but there are situations where a particular form might not have a corresponding model(s). For example, an arbitrary search form.
Based on my current research, there are two main ways of doing it as far as I can see,
Validate in the controller.
Is it possible to utilise the Rails validations in the controller? I really would prefer to use them over my own custom code.
Create an arbitrary class eg. called SearchForm and include the ActiveRecord::Validations
Should the class be stored with the models (even though it isn't really)?
The posts that recommended this approach indicated you have to stub out a bunch of methods for ActiveRecord such as save, save!, update_attribute, etc. This strikes me as not very Rubyesque at all!
Any other suggestions?
Absolutely #2. ActiveModel::Validations API is what you're looking for
class ArbitrarySearch
include ActiveModel::Validations
attr_accessor :query
validate :query, :presence
end
As for where this should go, yes, it should go in app/models. If you're like me and think the mix of models extending ActiveRecord::Base and those that don't coexisting within the same directory smells funny, consider adding the following to your config/application.rb file
config.autoload_paths += Dir["#{config.root}/app/models/**/"]
Now, you can organize your model files in whatever way you like. For me I have
- app
|
|- models
|
|- table
|- tableless
|- observer
and I drop classes like your ArbitrarySearch class into app/models/tableless/arbitrary_search.rb.
There is a great gem to get this and other common functionality you use within ActiveRecord models into generic non-table-based model classes called active_attr.
ActiveAttr is a set of modules that makes it easy to create plain old ruby models with functionality found in ORMs, like ActiveRecord, without reinventing the wheel. Think of ActiveAttr as the stuff ActiveModel left out.
I have an ActiveRecord model Reservation.
It got to the point that the class is to large and does too much.
I would like to split it into a few different ones and place those under the Reservation module.
Unfortunately this will break the app.
At this moment I see following options:
namespace it to something like ReservationConcerns or similar
add the functionality to the Reservation class itself, but physically move it to the subdir (Reservation would be in app/models/reservation.rb, Reservation::Pipeline would be in app/models/reservation/pipeline.rb etc).
So the question is how to structure the different concerns of a feature already having it as one single, bulky class without breaking the app.
If you want to split up a Ruby class into different components without changing its public interface, one solution is to use modules:
# app/models/reservation.rb
class Reservation < ActiveRecord::Base
# associations, validations, etc.
include Pipeline
end
# app/models/reservation/pipeline.rb
module Reservation::Pipeline
def some_pipeline_method
# ...
end
def other_pipeline_method
# ...
end
end
ActiveRecord also provides observers, which "is a great way to reduce the clutter that normally comes when the model class is burdened with functionality that doesn't pertain to the core responsibility of the class". Observers often make heavy use of the ActiveModel::Dirty methods.
These suggestions are complimentary: modules can help you group your interface into more local chunks, while observers can make backend details more self-contained. From here, it's difficult to be more specific without knowing exactly what pieces you have that you're trying to break out.
I am using Ruby on Rails 3.0.7 and I have tree classes what behavior is almost the same (and also the code in them model files). All those have a name and a description attribute, run same validation methods and for both there is a before_save callback that maintains data consistent providing the same functions.
I would like to refactor validation methods and callbacks in a separated class\model (I think I have to locate them related files in the \lib folder of my application).
What I have to do to make that? What code I have to add in my classes and what in the refactoring class\model?
Well, you could just make a super class from which your three models inherit. I tend to put the abstract base class in app/models alongside the models themselves.
# app/models/thing.rb
class Thing < ActiveRecord::Base
# common code goes here, such as
before_save ...
validates_length_of :foo
end
# app/models/red_thing.rb
class RedThing < Thing
# methods specific to RedThing go here
end
# app/models/blue_thing.rb
class BlueThing < Thing
# methods specific to BlueThing go here
end
If your Things have many differences such that it doesn't make sense to group them like this, you'd want to use a module instead, which is a only bit more complicated.
Rails guides has info here:
http://guides.rubyonrails.org/active_record_validations_callbacks.html#creating-custom-validation-methods
What are the advantages and disadvantages of creating a module like:
module Section
def self.included(base)
base.class_eval do
has_many :books
end
end
def ensure_books
return false if books <= 0
end
end
...where ActiveRecord methods are used in the module instead of directly on the class(es) they belong to?
Should modules be used for methods like this?
The most obvious advantage is that you can take functionality that is shared and put it into a single place. This is just a general advantage of keeping your code organized and modularized (no pun intended) – and you should, of course, do that
Using Active Record methods does not make these Modules special in any way.
The most obvious disadvantage is that your code, as written, is a little more complex. You can't use validates_presence_of in a module directly because it does not inherit from ActiveRecord::Base. (Rails 3 is supposed to make it easier to selectively extend your own classes/modules with bits of ActiveRecord-Functionality
Instead, you need to call the Active-Record-Methods on your model class when your model is included:
module FooHelper
def self.included(other)
other.send(:has_many, :foos)
end
end
So the prime disadvantage is that your code gets a little harder to read.
If you are just breaking up a single class into separate parts and don't need to reuse the code somewhere else, you could use the concerned_with-pattern which works by reopening classes.
On the other hand, If you need more functionality, like configuration parameters for your extension, consider writing a plugin
This code can be shared by models (classes).