1

From what i have read using a scope in Rails is more efficient as your querying the model directly as opposed to an instance variable which goes via the controller to the model (thats how i see it?)

So i have this query in my controller

@animal_location = User.select(:town).map(&:town).uniq
["Cardiff", "Newport"]

and then this scope in my model

scope :uniq_towns, ->() {
 select("town").group("town")
}
#<ActiveRecord::Relation [#<User id: nil, town: "Cardiff">, #<User id: nil, town: "Newport">]>

In my view to access the town value using @animal_location = User.select(:town).map(&:town).uniq I can access like

<% @animal_location.each do |loc| %>
  <%= loc %>
<% end %>

or if i used the scope and went with @animal_location = User.uniq_towns, in my view i would use

<% @animal_location.each do |loc| %>
  <%= loc.town %>
<% end %>

My first question is would my scope be quicker in this instance and secondly is my scope correct as i am getting User id: nil as part of the hash

Thanks

1
  • 1
    I don't think scoped queries are more efficient than regular queries. They just require less typing to call when needed. Commented Oct 28, 2014 at 15:33

1 Answer 1

3

It depends on what your source meant by "efficient". Scopes are designed to keep code DRY, in a sense of "Don't Repeat Yourself", and implement an "extract method" refactoring pattern for ActiveRecord (AR) queries. They are easy to maintain.

Why use it? If you use the same query in multiple places consider the situation when you need to change it everywhere. You have to find&replace all occurrences. This way is error-prone and causes more differences in version control that are harder to keep track of.

Extracting this query into a method seems like a logical solution. Class method? No, maybe you shouldn't, but simply put scopes are just that. By using scopes you will:

  • Get a single place to construct a query with a certain meaning (and use it throughout the app)
  • Be pretty sure that the result of a scope is chainable, because the result is a valid AR relation (and you can apply scopes on top of it)
  • Provide your query's meaning a good readable name to keep controller code readable (using scopes in views is valid, but against MVC that Rails follows)

You have:

@animal_location = User.select(:town).map(&:town).uniq

First and foremost, I fail to see why map and group are needed, this works fine too and uses SQL DISTINCT:

@animal_location = User.select(:town).uniq

This looks short enough to be readable. But let's demonstrate scopes here. In your model issue this:

scope :uniq_towns, ->() {
 select("town").uniq
}

...so you can write this in your controler:

@animal_location = User.uniq_towns

There are also other ways to tackle this situation, like before_filter, but it's beyond the scope of the question.

Sign up to request clarification or add additional context in comments.

1 Comment

thank you for your in depth answer, certainly clears scopes up for me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.