Blankman
Blankman

Reputation: 267370

In Rails, shouldn't we create a service layer, instead of jumbling logic into a controller?

Say I have a controller that returns a list of users. The users are to be returned from memcache if the cache key exists, otherwise hit the mysql db. This logic will be re-used in say a web service layer or something.

action:

def list

  if in cache
     @userlist = ...
  else
     @userlist = User.all()
  end

end

In the Java world, you would create a UserService layer that would wrap additional logic (like first checking the cache layer, etc.).

In rails it people tend to put all this logic in the controller.

What is the Rails 'best-practise' here?

Upvotes: 9

Views: 5517

Answers (4)

chischaschos
chischaschos

Reputation: 557

Now days there are more points of view on this topic, example:

http://blog.carbonfive.com/2012/01/10/does-my-rails-app-need-a-service-layer/

http://rubysource.com/ddd-for-rails-developers-part-1-layered-architecture/

My default advice is to follow OOP principles, keept things simple, do not to violate SRP and create meaningful abstractions.

Upvotes: 4

Nicholas Henry
Nicholas Henry

Reputation: 355

There seems to be a "small" movement in the Rails community to establishing a service layer in some projects/applications. In 2010, I worked on a project where we introduced a apps/services directory to store service objects. We found that the application logic was spread across controllers and models and this helped encapsulate such behaviour. James Golick has an interesting post on the subject. Check out Pat Maddox's comments as well:

http://jamesgolick.com/2010/3/14/crazy-heretical-and-awesome-the-way-i-write-rails-apps.html

Upvotes: 15

Fábio Batista
Fábio Batista

Reputation: 25290

The "Rails way" is: skinny controllers, fat models.

You can simply change the model to support cache:

class User < ActiveRecord::Base
  def self.all
    @cached[:all] ||= super
  end
end

Or create an injector to support cache the way you want for multiple models:

class User < ActiveRecord::Base
  include CacheInjector
end

Remember: Ruby, as a dynamic language, is very easy to extend. Mixins, interceptors, aspects, all those things that are a PITA to implement in Java, are very easy and natural on Ruby. Give it a try.

Upvotes: 9

Jimmy
Jimmy

Reputation: 9815

Why not perform that checking in the model and just call a model function from your controller. Fat models and skinny controllers

Upvotes: 2

Related Questions