I have three Models. Both makes and models table have name column inside.
class Review < ActiveRecord::Base
belongs_to :model
end
class Model < ActiveRecord::Base
belongs_to :make
has_many :reviews
end
class Make < ActiveRecord::Base
has_many :models
end
In Active Admin on Index Page I want to sort reviews by make and model.
I figured out how to sort it by model, because it has key the reviews table.
Tried a lot of things. Nothing works to sort by make name. I was able to list though.
ActiveAdmin.register Review do
column "Model", sortable: 'model_id' do |p|
p.model.name
end
column "Make", sortable: 'make_id' do |review|
review.model.make.name
end
end
Only sorting by model name works. I think if I add make_id to Reviews it will be working, but it seems redundant, cause a chain like review.model.make perfectly works
Let's say a review is a score between 1 and 5.
You will have to compute the average value for each make.
To compute an average value for a make, do:
reviews_sum = 0
total_reviews = 0
make.models.each do |model|
model.reviews.each do |review|
reviews_sum += review
total_reviews += 1
end
end
Then:
average_review = reviews_sum / total_reviews.to_f # I am using to_f to convert total_reviews from integer to float. This way you can have a float result.
I advice you to create an make_average_review(make_id, average_review)
This way you can store/update your average review for every make and then sort by make
Related
I have the following models in my Ruby on Rails application in which I'm using Postgres Database:
class Sale < ApplicationRecord
has_many :line_items
end
class LineItem < ApplicationRecord
belongs_to :sale
end
There are now 2 things I want to achieve:
First, I'd like to create an index page in ActiveAdmin for Sales, so I could, for each sale, display the sum of line items prices.
What I already tried, which doesn't work very well(it's very slow):
ActiveAdmin.register Sale do
actions :index
remove_filter :line_items
index do
column :created_at
column :price do |sale|
sale.line_items.sum(:price)
end
end
end
Second, I'd like to make this column sortable - would it be possible?
My suggestion for your case above you can just group based sale_id and then sum the price and to the sort with method below, reverse will get you descending order
LineItem.group(:sale_id).sum(:price).sort_by{|k, v| v}.reverse
if you need probably top ten you can use first(10)
LineItem.group(:sale_id).sum(:price).sort_by{|k, v| v}.reverse.first(10)
Try registering a database view that sums the prices. The documentation on custom sorting should still apply. Links to tips and tricks like this can be found on the wiki.
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
My models are:
class Link < ActiveRecord::Base
has_many :votes
belongs_to :user
end
class Vote < ActiveRecord::Base
belongs_to :user
belongs_to :link
end
class User < ActiveRecord::Base
has_secure_password
has_many :links
has_many :votes
end
I have a page where I list all the links in the system. For each link I want to display both the current sum of all the votes as well as whether or not the user making the request has voted on that particular link (and if so what that vote's value was). I want to do this in the most efficient manner.
Currently in order to return the links and sums of the votes I have this in my Link controller:
def index
#links = Link.all(:joins => :votes, :select => "links.*, sum(votes.value) as votes_total", :group => "links.id")
end
Which works well and gives me all my information in a single call. So my question is, do I need to make a second query to return the vote (if it exists) for current_user or can I incorporate that into my first query somehow?
Additionally, perhaps I should set up some kind of sum_caching in the database but I'm not sure the best way to go about that either. Any thoughts?
You could do something like this:
#links = Link.
joins(:votes).
select(
"links.*, sum(votes.value) as votes_total, sum(case votes.user_id when #{current_user.id} then votes.value else 0 end) as current_vote",
:group => "links.id"
)
That would give you the current user's vote value as #links.first.current_vote. Of course, if your system has votes with a value of zero, it doesn't distinguish between "current user voted 0 on this link" and "current user did not vote on this link". You could add yet another selected value (sum(case votes.user_id when #{current_user.id} then 1 else 0 end) as current_vote_exists) to handle that, I suppose.
Naturally, you want to be really careful when interpolating into SQL like this, and/or look up the SQL-sanitizing tools that come with ActiveRecord.
I want to make a line graph of how much money a certain employee has used each month, the information is scattered accross 3 tables. The desired output is an Array as follows.
[["08-Aug-11",500],["02-Feb-11",200],["03-Mar-12",260],["05-May-12",140],["09-Sep-11",0],["05-May-11",500],["12-Dec-11",420],["01-Jan-12",260]]
Models involved as bellow
class Employee < ActiveRecord::Base
has_many :cases
end
class Case < ActiveRecord::Base
belongs_to :employee
has_many :expenses
end
class Expense < ActiveRecord::Base
belongs_to :case
end
I have a case table, which has many expenses, and I want to group the expenses by a date value inside case, and sum up a value inside expenses to generate data needed for a line graph on how much money was spent by a particular employee each month.
This wouldn't be a problem if I wanted monthly group ups by all the cases,
but since cases will be selected as well, and that the cases are grouped by month, I'm pretty sure theirs a spiffy sql query to do this, but can't come up with it.
Can anyone give me a pointer? or is there a better approach to generate the data?
By far, this is what I've come up with
expenses = Case.where( "id IN (?)", employee.cases.all.map{ |x| x.id } )
.group_by { |t| t.case_completion_date.beginning_of_month }
expenses.each do |monthly_expenses|
total_price = 0
monthly_expenses[1].each do |active_case|
if active_case.estimates.any?
total_price = total_price + active_case.expenses.first.price
end
end
expenses_array << [ monthly_estimate[0].strftime( "%m-%b-%y" ), total_price ]
end
Rails 3.1
I'll simplify my application to get at my question.
I have two tables: Items and Reviews
Items has a column "Average_Rating" and Reviews has a column "Item_ID" and "Rating"
For each item, I'd like to store the average rating for its corresponding reviews. Although I can't figure it out, I feel like what I want to do is add something to the create and update methods in the Reviews Controller along the lines of:
#review = Review.find(params[:id])
#item = Item.find(#review.Item_ID)
reviews_to_sum = Reviews.find_by_item_id(#item.id)
#item.Average_Rating = reviews_to_sum.Rating.sum/reviews_to_sum.count
I recognize, however, that the above probably isn't close to correct... I'm a beginner and I'm stuck.
And I do want to store the Average_Rating in the database, as opposed to calculating it when I need it, for a variety of reasons.
class Item < ActiveRecord::Base
has_many :reviews
end
class Review < ActiveRecord::Base
belongs_to :item
after_save do
item.update_attributes average_rating: item.reviews.average(:rating)
end
end