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
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:
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.