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.
Related
I am a newbie in Ruby on Rails. Coming from a C# and Java background, Ruby on Rails seems bizzare, yet interesting at the same time. It's almost like coming from a class-based object-oriented world to the prototyping concept of JavaScript, or even to a functional language.
Anyways, in a traditional C# or Java MVC application, I tend to keep my models and controllers as clean as possible, extracting the business logic into service classes. My models are just POCOs/POJOs (with some calculated fields and validation at most). And my controllers just process incoming requests (relying heavily on dependency injection) and then return a view or JSON.
Yet, I do not see any clear pattern in the RoR world. Some people tend to put all their business logic into controllers, some put it into models (with ActiveRecords, it kind of makes sense, although I don't like it).
And then there is the concept of Concerns. Are they the right place to extract my business logic, instead of using services? If yes, could you include an example of proper Concers use? I still struggle with the concept of modules (are they more of namespaces, or rather interfaces)? As said at the beginning, Ruby seems like a whole new galaxy to me.
This question could get into the weeds a bit as it brings in a lot of personal preferences. However here is my take on it.
First, Concerns are not a replacement for Service classes. Concerns are a clean and nifty way to manage your mix-ins. If you are new to Ruby, mix-ins are basically a way of injecting instance and/or class methods into existing classes. For example, given these classes:
class EvilRobot < ActiveRecord::Base
def destroy(target)
...
end
end
class OrneryTeenAger < ActiveRecord::Base
def destroy(target)
...
end
end
you could dry out the code with:
require 'active_support/concern'
module EvilTools
extend ActiveSupport::Concern
included do
def destroy(target)
...
end
end
end
class EvilRobot < ActiveRecord::Base
include EvilTools
end
class OrneryTeenAger < ActiveRecord::Base
include EvilTools
end
I think that the vast majority of Rails developers, myself included, go for a fat-model, thin controller design. Just how fat though is a matter of taste. I also tend to move functionality to classes under lib if they don't fit logically within a model, or extract into an engine or gem.
I would say jpgeek reaction is part of the answer. The is a lot of movement towards service objects to clean up fat models or large controllers actions. Just create an app/services folder and create service classes like:
class TargetDestructionService
def initialize(shooter, target)
#shooter = shooter
#target = target
end
def execute
#Lot of code that causes the destruction of the target.
end
end
Then in your model or controller you would call:
TargetDestructionService.new(EvilRobot.new, Human.new).execute
Here is a nice article about it: https://blog.engineyard.com/2014/keeping-your-rails-controllers-dry-with-services
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.
In the Rails application I’m currently developing I have many “request” models. We are using a lot of web services and we have a lot of different requests to those services, each of them with their own logic (mostly validations). So they are all grouped in a module as a namespace:
module Request
end
So now every request is something like:
class Request::SendSomeData
end
So far, so good… The thing is that we are going to have a lot of such requests which will share some common logic. It is easy to include the module
class Request::SendSomeData
include Request
end
… (so it will act both as a namespace and a mixin), but I was wondering if there is a way to make it without the include (as it is going to be some kind of code repetition).
Is there a way for Ruby to put some instance methods to all the classes in a module’s namespace without explicitly including the module?
In other words can I have something like:
module Request
def someMethod
end
end
and
class Request::SendSomeData
end
and be able to use
Request::SendSomeData.new.someMethod
at the same time?
What you are asking can't be done without some evil hackery.
You either have too many classes, or are focusing on an issue that is too unimportant. It's only one line of code per class.
An alternative is to create a base model class, as I have previously described in another question, but this requires the derived classes to each call set_table_name, so it won't save you any typing.
I've read that the main service provided by a module is to contain and group similar functions that are needed by several objects. But is it a good practice to create a module for something like a parser even if you are certain that only one object will ever require its services?
Modules serve two purposes. The first as you have noted is to allow functionality to be added to a diverse set of classes (diverse meaning outside the inheritance tree). The second an by far more common use is to organize the names space. When you see code like ActiveRecord::Base or BSON::ObjectID the authors of these gems have placed their functionality in a module, ActiveRecord and BSON respectively, that prevents their class names from conflicting with the applications they are included in or other libraries.
With the parser you mentioned, it sounds to me like you want to construct a singleton class rather then a module.
It can help for organization to create a module even if you are using it in one place. For example you might have a lot of methods that are all related, but not really related to the code you are including the module in. This is similar to the the organization that a class provides, except that a module isn't focused on an object.
main service provided by a module is
to contain and group similar functions
that are needed by several objects
I would re-word it to "group similar functions that might be needed by at least one object". It's very frequent that you don't know how many classes will end up including or extending a module (for example if you are writing a library)
Independently of that, I see two more "main purposes":
They are a way to provide scopes (you can package several classes and other modules inside one module).
They have a callback called included. This might seem trivial, but that callback is key in a lot of interesting meta-programming techniques.
I would go for a class (if you got not too much code). Place it under /lib
class Parse
def self.xml(xml_string)
...
end
end
Parse.xml("<xml></xml>")
You can call it from anywhere.
http://en.wikipedia.org/wiki/Separation_of_concerns
Modules are indeed a group of similar functions. If you got a lot of parsing code you could do:
class Xml
acts_as_parser
end
class Json
acts_as_parser
end
...
acts_as_parser will load the group of functions from the module.
But is it a good practice to create a module for something like a parser even if you are certain that only one object will ever require its services?
Yes.
In Ruby, modules help a whole lot with separation of concerns and are very good for doing "aspect-oriented" programming (i.e., fun with mixins).
# Basic Hierarchy
class X
def say ; 'X' end
end
class Y < X
def say ; super + 'Y' end
end
y = Y.new
y.say #=> 'XY'
# Throwing in an aspects/mixins
module A
def say ; super + 'A' end
end
class Y
include A
end
y.say #=> 'XAY'
# Throwing in another aspects/mixins
module B
def say ; super + 'B' end
end
class Y
include B
end
y.say #=> 'XABY'
When faced with an excessively large class, sometimes I split it up into a couple of modules based on its functionality, and have a virtually empty class just include those modules.
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).