i have a 'Course' model that has the following attributes;
Course
Price - float
Featured - boolean
My question would be the following, I need 4 lists in my controller, recent courses, paid courses, free courses and featured courses.
It would be good practice to write my controller as follows?
def index
@courses = Course.order(created_at: :desc)
@free_courses = []
@courses.map {|c| @free_courses << c if c.price == 0}
@premium_courses = []
@courses.map {|c| @premium_courses << c if c.price> 0}
@featured_courses = []
@courses.map {|c| @featured_courses << c if c.featured}
end
Or do the consultations separately?
def index
@courses = Course.order(created_at: :desc)
@free_courses = Course.where("price == 0")
@premium_courses = Course.where("price > 0")
@featured_courses = Course.where(featured: true)
end
I checked through the logs that the first option is more performance but I am in doubt if it is an anti partner.
Thanks for all!
The second approach will become faster than the first as the size of the Course table increases. The first approach has to iterate over every record in the table 4 times. The second approach creates a Relation of only the records that match the where clause, so it does less work.
Also, the second approach has the advantage of laziness. Each query is only run at the time it is used, so it can be changed further along the code path. It's more flexible.
Note that it would be an improvement to the second approach to create scopes on the Course model that handles the logic. For example, one each for courses, free_courses, premium_courses and featured courses. This has the advantage of putting database logic in the model instead of the controller, where it can more easily be reused and maintained.
第二种方法更好,因为当您使用.where()方法时,您是将查询安排在数据库本身而不是控制器中。
It is generally bad practice to iterate over all records in the database in Rails (ie Course.map
or Course.all
) both for performance and memory usage. As your database grows this becomes exponentially problematic. It's much better to use Course.where()
methods. You'll probably want a default sort order so you can add with one line in your model.
default_scope { order(created_at: :desc) }
Then you can just do this in controller and they'll have the sort by default:
@courses = Course.all
I would also suggest adding scopes to your model for easier access. So in your course.rb file
scope :free -> { where("price == 0") }
scope :premium -> { where("price > 0") }
scope :featured -> { where(featured: true) }
Then in your controller you can just do:
@courses = Course.all
@free_courses = Course.free
@premium_courses = Course.premium
@featured_courses = Course.featured
These scopes can also be chained if you need to combine those so you could do things like:
@mixed_courses = Course.premium.featured
As others have explained, Model.where()
executes the selection of data by passing sql inside where("Write Pure SQL QUERIES HERE")
where as regular ruby enumerable methods ( .map
) iterate over array which must be instantiated as ruby objects. That's where the memory / performance issues take the hit. It's ok if you're working with small data sets, but anything with data volume will get ugly.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.