Why are Rails areas preferable if intricate controllers are faster?

I tried to connect Arel queries with scopes, instead of just using some long logic that I wrote in the controller. But the scope is slower than just getting all the records and then sifting through them using some logic. Then I wonder why areas are better.

That's what I'm doing:

  • There are many answers to the question.
  • the answer belongs to one question
  • The question has a column "question_type", which I use to sort it

First, the path of the area ...

in the .rb question:

scope :answered, joins(:answers).order('answers.created_at desc') scope :dogs, where(:question_type => "dogs") scope :cats, where(:question_type => "cats") scope :mermaids, where(:question_type => "mermaids") 

in questions_controller.rb:

 @dogs_recently_answered = Question.answered.dogs.uniq[0..9] @cats_recently_answered = Question.answered.cats.uniq[0..9] @mermaids_recently_answered = Question.answered.mermaids.uniq[0..9] 

Then in the view, I look at these instance variables (which are now arrays containing no more than 10 elements) and display the results.

Here are a few times to load the page (five times):

Completed 200 OK at 535ms (Views: 189.6ms | ActiveRecord: 46.2ms)

Completed 200 OK in 573ms (Views: 186.0ms | ActiveRecord: 46.3ms)

Completed 200 OK in 577ms (Views: 189.0ms | ActiveRecord: 45.6ms)

Completed 200 OK at 532ms (Views: 182.9ms | ActiveRecord: 46.1ms)

Completed 200 OK in 577ms (Views: 186.7ms | ActiveRecord: 46.9ms)

Now, the way of the messy controller ...

 @answers = Answer.order("created_at desc") @all_answered = [] @answers.each {|answer| @all_answered << answer.question} @recently_answered = @all_answered.uniq @dogs_all_answered = [] @cats_all_answered = [] @mermaids_all_answered = [] @recently_answered.each do |q| if q.question_type == "dogs" @dogs_all_answered << q @dogs_recently_answered = @dogs_all_answered[0..9] elsif q.question_type == "cats" @cats_all_answered << q @cats_recently_answered = @cats_all_answered[0..9] elsif q.question_type == "mermaids" @mermaids_all_answered << q @mermaids_recently_answered = @mermaids_all_answered[0..9] end end 

And here is the time it takes to load the page now (five times):

Completed 200 OK in 475ms (Views: 196.5ms | ActiveRecord: 34.5ms)

Completed 200 OK in 480ms (Views: 200.4ms | ActiveRecord: 36.4ms)

Completed 200 OK in 434ms (Views: 198.2ms | ActiveRecord: 35.8ms)

Completed 200 OK in 475ms (Views: 194.2ms | ActiveRecord: 36.4ms)

Completed 200 OK in 475ms (Views: 195.0ms | ActiveRecord: 35.4ms)

So...

In addition to readability, what can be gained by honing the request with scope? Does it get faster when there are more entries?

+4
source share
2 answers

Firstly, I’m not sure that I understand how the question may differ from the unique one, so I would try to delete it. I do not know the logic of your data, so this may not be applicable, but this is an additional step that you could avoid.

Here's how I get to it:

 scope :answered, joins(:answers).order('answers.created_at desc') scope :recent, take(10) scope :dogs, where(:question_type => "dogs") scope :cats, where(:question_type => "cats") scope :mermaids, where(:question_type => "mermaids") @dogs_recently_answered = Question.answered.dogs.recent @cats_recently_answered = Question.answered.dogs.recent @mermaids_recently_answered = Question.answered.dogs.recent 

This moves the TOP query part to the database where it belongs, rather than retrieving all rows, and then discarding all but 10. Depending on your unique criteria, you can also use a scope, for example

 scope :unique, select('DISTINCT column_name') 

and then you can use Question.cats.unique.recent and get it all in one quick query that uses the relational algebra that the database systems are designed for.

+4
source

I think that in this case the reasons are slower - this is because they lead to 3 separate database queries, while the other approach uses the knowledge that all three results can be satisfied with the only query you use.

Assuming that this is so, it is not surprising that the scopes fulfill 3 separate requests, since the system does not know when you call the first one, which you are going to call immediately. Perhaps there is an optimization strategy that would be reasonable for this scenario, but I do not know that ActiveRecord implements it.

In any case, this is one of the shortcomings of the sphere in this particular case. I like domains because they are clean / understandable, flexible, and encapsulated by a named abstraction for the query. AFAICT, in many scenarios they are noticeably no slower than the equivalent direct request.

+1
source

All Articles