Say I have 2 models, Category and Article; given the following association:
Category has_many :articles.. and Article belongs_to :category
If I do.. Article.all I get an array back in ASC order.
Now, Rails allows me to query a Category's Articles with: Category.find(:id).articles... but in doing so I get an array back in DESC order.. is there a way to override the default behavior of this so that I can order this array using x column in the Article's table without having to chain .order('column_name') everywhere I do this?
Hope this makes sense, thanks.
You could specify the order when define association.
class Category < ActiveRecord::Base
has_many :articles, :order => "updated_at DESC"
end
For Article.all's order, you could define the default_scope
class Article < ActiveRecord::Base
default_scope { order('updated_at DESC') }
end
Related
In Ruby I can sort some objects by invoice number in descending order like:
#app.sample_sales.sort_by {|sale| -sale.payload['invoice_number'].to_i }
However I can't quite get it to work using Rails:
#app.sample_sales.order("payload->'invoice_number' desc")
I've also tried:
#app.sample_sales.order("payload->'invoice_number::integer' desc")
Models
#sample_app.rb
class SampleApp < ApplicationRecord
has_many :sample_sales, dependent: :destroy
end
#sample_sale.rb
class SampleSale < ApplicationRecord
belongs_to :sample_app
end
Your syntax is not correct. Here is a good one:
#app.sample_sales.joins(:payload).order('payload.invoice_number desc')
I might update this answer when you've shared your model's associations. 😉
product.rb
has_many :votes
vote.rb
belongs_to :product
Every time, i use sorting in my index controller:
index_controller.rb
def index
#products = Product.all.sort { |m| m.votes.count }
end
So, i think it would be good to cache votes count for each product (create additional column votesCount in products table)?
If yes, can i preform that using before_save and before_delete callbacks in vote.rb model?
Or what is the best practice method?
Give me some examples please.
I guess you are looking for counter_cache
The :counter_cache option can be used to make finding the number of belonging objects more efficient
Consider these models:
class Order < ActiveRecord::Base
belongs_to :customer, counter_cache: true
end
class Customer < ActiveRecord::Base
has_many :orders
end
With this declaration, Rails will keep the cache value up to date, and then return that value in response to the size method.
Although the :counter_cache option is specified on the model that includes the belongs_to declaration, the actual column must be added to the associated model. In the case above, you would need to add a column named orders_count to the Customer model
I have a simple Customer model with a has many relationship with a Purchase model.
class Customer < ActiveRecord::Base
has_many :purchases
end
I am repeatedly finding that I need to order Customer.purchases in my views in the following way:
#customer.purchases.joins(:shop).order("shops.position").order(:position) #yes, two orders chained
In the interest of keeping things DRY, I'd like to put this somewhere centralized so I don't have to repeatedly do it. Ideally, I'd like to make it the default ordering for Customer.purchases. For example:
class Customer < ActiveRecord::Base
has_many :purchases, :order => joins(:shop).order("shops.position").order(:position)
end
Obviously the above doesn't work. How should I do this?
In your customer model you specified joins(:shop) is the value for the key :order. I think here is the problem, So you can use the joins as a key instead of order like below,
class Customer < ActiveRecord::Base
has_many :purchases, :joins => [:shop], :order => "shops.position"
end
I think it may work.
In your purchases model, you can create a class method:
Purchase.rb:
def self.order_by_position
joins(:shop).order("shops.position").order(:position)
end
Then you can say things like:
#customer.purchases.order_by_position
Purchase.order_by_position
You could create a method on Customer that returns ordered purchases:
class Customer < ActiveRecord::Base
has_many :purchases
def ordered_purchases
purchases.joins(:shop).order("shops.position").order(:position)
end
end
and call #customer.ordered_purchases from your views.
I have piece and lineup joined by piece_lineup
piece_lineup is a has many through relationship join and has an attribute 'position'
how would I sort a list of pieces based on their related position attribute in the join model.
thanks
Try this:
class Piece < ActiveRecord::Base
has_many :piece_lineups
has_many :lineups, :through => :piece_lineups,
:order => "piece_lineups.position"
end
Now piece.lineups is sorted as per your requirement.
I think this may now do:
Piece.joins(:piece_lineups).order("piece_lineups.some_attribute DESC")
If you just want the order of pieces according to 'attribute', then 'joins' is best.
If you do want this is the model instead, then you only need:
class Piece < ActiveRecord::Base
has_many :lineups, :order => 'lineups.postion'
end
Try
Piece.includes(:piece_lineups).where('some condition').order('piece_lineups.position')
I have 2 models:
class Video < ActiveRecord::Base
belongs_to :categories, :foreign_key => "category", :class_name => "Category"
end
class Category < ActiveRecord::Base
has_many :videos
end
This is fine so far, in my videos controller for the index page I have:
def index
#videos = Video.all(:joins => :categories)
etc, etc
end
The above produces the following SQL Query: SELECT videos.* FROM videos INNER JOIN categories ON categories.id = videos.category
Which is fine up to a certain point, basically I need to get the category name (a field in that table) that way I don't have to do another call in the view to get category name based on the category id. Any ideas?
Thank you, and yes I am new to ruby, I tried reading the API but couldn't find much help there.
If think the association in your Video class is set up incorrectly. It should be:
class Video < ActiveRecord::Base
belongs_to :category
end
You can do #videos = Video.all(:include => :category). This will retrieve the video and associated category records using a single SQL statement.
Incidentally, your :class_name option on the belongs_to association is redundant because ActiveRecord will already have automatically inferred the class name from the association name. You should only use this option if you want to have an association name that is different from the underlying class e.g. authors/Person.
join_condition = " ,categories where INNER JOIN categories ON categories.id=videos.category"
#videos = Video.all(:joins => join_condition)
try this