问题
I am trying to use a default scope to impose a sort order on the model QuizCategoryWeight. The goal is to get @possible_answer.quiz_category_weights to return the weights in sorted order.
Update: I have narrowed the problem down to the fact that default scopes seem to work for me as long as they just have an 'order' method but not when the 'includes' method is chained with the 'order' method. However, this chaining does work for named scopes.
Could it be my development environment? Or is this a bug in Rails perhaps?
I am using windows, so maybe that's the problem. Currently on ruby 2.0.0p645 (2015-04-13) [i386-mingw32] and Rails 4.2.4...
The following, using a default scope on QuizCategoryWeight, does not seem to work:
class QuizCategoryWeight < ActiveRecord::Base
#trying to use a default scope, but does not work
default_scope { includes(:quiz_category).order("quiz_categories.sort_order") }
belongs_to :possible_answer, inverse_of: :quiz_category_weights,
class_name: 'QuizPossibleAnswer', foreign_key: 'possible_answer_id'
belongs_to :quiz_category
end
class QuizPossibleAnswer < PossibleAnswer
has_many :quiz_category_weights,
#does not work whether the line below is used or not
->{ includes(:quiz_category).order("quiz_categories.sort_order") },
inverse_of: :possible_answer,
dependent: :destroy,
foreign_key: 'possible_answer_id'
end
class QuizCategory < ActiveRecord::Base
default_scope { order :sort_order }
end
With a named scope, it does work. However, this means that I have to add an argument to my form builder to use the collection 'f.object.quiz_category_weights.sorted'.
class QuizCategoryWeight < ActiveRecord::Base
# named scope works...
scope :sorted, ->{ includes(:quiz_category).order("quiz_categories.sort_order") }
belongs_to :possible_answer, inverse_of: :quiz_category_weights,
class_name: 'QuizPossibleAnswer', foreign_key: 'possible_answer_id'
belongs_to :quiz_category
end
class QuizPossibleAnswer < PossibleAnswer
has_many :quiz_category_weights,
inverse_of: :possible_answer,
dependent: :destroy,
foreign_key: 'possible_answer_id'
end
回答1:
I think there is a bug with using 'includes' with a default scope, either in the Rails framework generally or in my windows version.
However, I've found that using 'joins' does work. I'm not using any of other the attributes from QuizCategory so it's more appropriate to my use case as well: I only want to sort using the 'sort_order' attribute from the joined table.
The fixed code is:
class QuizCategoryWeight < ActiveRecord::Base
default_scope { joins(:quiz_category).order("quiz_categories.sort_order") }
belongs_to :quiz_category
end
回答2:
The includes
method was introduces for relations to give Rails a hint to reduce database queries. It says: When you fetch Objects of type A, also fetch associated objects, because I need them later, and they should not fetched one by one (the N+1 queries problem)
The includes
was first implemented with two database queries. First all A, then all B with one of the ids from A. Now includes
often uses a sql join to have only one database query. But this is an internal optimisation.
The concept is object oriented, you want objects from A, then you retrieve the B through the A. So I think, if you set the order from the included B back to A, you are doing more than was meant for the original includes
.
来源:https://stackoverflow.com/questions/32896215/rails-4-relation-is-not-being-sorted-has-many-association-w-default-scope