Blog › Ruby

Rails Best Practices 4: Put method in the right model

In today’s post I will show some optimization we can do for models. I’ll focus on how to put methods inside the right model and delegation to get a better code.

1. Put method in the right model

In our example, suppose we want to represent the animal world by creating a model Kind that represents types of animal and an Animal models representing animals.
For each type (quadrupedal, bipedal, bird) there are different animals that justify the has_many: animals relation defined in the following code.

1
2
3
4
5
6
7
8
9
10
11
12
13

class Kind < ActiveRecord::Base
has_many :animals

def find_herbivores
self.animal.find(:all,
:conditions => { :eat_herb => true })
end

end

class Animal < ActiveRecord::Base
belongs_to :kind
end

Next, we define a method “herbivores” within the AnimalsController that, given a type of animal return all the herbivorous contained in that type.

1
2
3
4
5
6

class AnimalsController < ApplicationController
def herbivores
@kind = Kind.find(params[ :id])
@animals = @kind.find_herbivores
end
end

The flaw in this code is to have defined the method find_herbivores inside the Kind model when in fact refers to a property of the Animal class.

Let’s see how to rewrite it in proper way, using a named_scope in the Animal model.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

class Kind < ActiveRecord::Base
has_many :animals
end

class Animal < ActiveRecord::Base
belongs_to :kind
named_scope :herbivores,
:conditions => { :eat_herb => true }
end

class AnimalsController < ApplicationController
def herbivores
@kind = Kind.find(params[ :id])
@animals = @kind.animals.herbivores
end
end

2. Delegate

In this second example, suppose we have a Location class associated with an owner and want to show owner’s data in the Location’s view.
A first simple implementation is the following:

1
2
3

class Location < ActiveRecord::Base
belongs_to :owner
end

And in the view:

1
2
3
4

<%= @location.owner.name %>
<%= @location.owner.city %>
<%= @location.owner.street %>
<%= @location.owner.email %>

This type of implementation is very common in Rails applications, but you can make it more elegant by using the construct “delegate” as follows:

1
2
3
4
5

class Location < ActiveRecord::Base
belongs_to :owner
delegate :name, :city :street, :email :to => :owner,
:prefix => true
end

Now we can rewrite the view as follows:

1
2
3
4

<%= @location.owner_name %>
<%= @location.owner_city %>
<%= @location.owner_street %>
<%= @location.owner_email %>

The result does not change, but the code is certainly more elegant.

Find out where AI can save your company time.

One hour with our team: we map your processes, pick 2-3 concrete use cases and tell you what is worth doing first. No strings attached.

Book a free AI assessment
Subsidised finance

Incentives and grants for your software or AI project.

With specialised partners we check which incentives your project can access and prepare the paperwork and the financing plan.

  • Hyper-depreciation for 4.0 and 5.0 assets
  • National and regional grants
  • Financing plan
Book a free AI assessment