RoR sum related records during controller create - ruby-on-rails

I have tables = expenses and invlines (invoice lines).
Expense belongs_to Invline
Invline has_many expenses
Using the Invlines input form, I have the user select the Expenses.
When the Invlines record is saved, I would like to summarize the expenses and place into invline.price
In the Invlines controller I'm trying to use:
def create
#invline = Invline.new(params[:invline])
#invline.price ||= #invline.expenses.amount.sum
But, I get
undefined method `amount'
Ideas?
Thanks!

Replace:
#invline.price ||= #invline.expenses.amount.sum
with
#invline.price ||= #invline.expenses.sum(:amount)
The .expenses call returns a list of expenses, but only a particular expense has amount.

Related

Count total bookings by category - Rails

My BookingGroup has_many Booking. Booking contains column category where the data can be "adult" or "child_infant" or child_normal.
Now I want to count all total %child% and display it in my index view table
I was'nt sure whether this could be done in one line or I have to use a scope, this is where I stucked.
BookingGroup model
def search_by_category
bookings.visible.map(&:category).inject(:+)
end
Assuming category is a string column, you should be able to count it like that :
bookings.visible.where("category LIKE ?", "child%").count
bookings.visible.where(category: ["child_infant", "child_normal"]).count
We can use LIKE just as in SQL with active record
In your BookingGroup model
def search_by_category
bookings.visible.where('category LIKE ?', '%child%').size
end
But, if you do so for many booking_groups, your code will have N+1 queries issue. You can use eager load in your controller
#booking_groups = BookingGroup.joins(:bookings).select('booking_groups.*', 'count(*) as total_bookings').where('bookings.category LIKE ?', '%child%').group(:id)
Then you can
#booking_groups.first.total_bookings

Rails create multiple records at once from nested attributes on a different model

In my app I have model PurchaseOrder and PurchaseOrderList. When I create a purchase order it updates both tables purchase_orders and purchase_order_lists with a nested form.
Now I want to be able to add a button update stock on purchase_orders/show. When I click this button a new record will be created on table stockdiaries with same products, units and prices as on the purchase order.
The logic is that first I create a purchase order and then I click the button to update stock when goods are received.
The best I came up with is to create this method on PurchaseOrders controller:
def update_stock
#purchase_order_list = PurchaseOrderList.where(PURCHASE_ORDER: params[:ID])
#stockdiary = Stockdiary.create(PRODUCT: #purchase_order_list.PRODUCT, UNITS: #purchase_order_list.UNITS, PRICEBUY: #purchase_order_list.PRICEBUY)
flash[:notice] = "Stock updated successfully."
redirect_to(:action => 'show', :ID => #purchase_order.ID)
end
and in my purchase_orders/show:
<%= link_to "Update Stock", { controller: :purchase_orders, action: :update_stock, ID: #purchase_order.ID} %>
but it raises error
undefined method `PRODUCT' for
#<PurchaseOrderList::ActiveRecord_Relation:0x007f1efeff4898>
But there is a column PRODUCT on purchase_order_lists table.
Note that I included in the method only columns that are common to purchase_order_lists and stockdiaries as others (as id or status) are not concerned on this question. Columns names are capital as I'm building the app on existing db.
What is the correct way to create a stockdiary from a purchase order?
Updated
Rails is returning an an ActiveRecord Relation from this query:
#purchase_order_list = PurchaseOrderList.where(PURCHASE_ORDER: params[:ID])
This is because you used where, so ActiveRecord returns a relation that could potentially have multiple records in it. If you only want one record, or even if you know that there will only be one record then you should use find_by
So you can either do:
# change where to find_by
#purchase_order_list = PurchaseOrderList.find_by(PURCHASE_ORDER: params[:ID])
# and then this will work
#stockdiary = Stockdiary.create(PRODUCT: #purchase_order_list.PRODUCT, UNITS: #purchase_order_list.UNITS, PRICEBUY: #purchase_order_list.PRICEBUY)
OR... If you want where or there might be multiple records, then you can loop:
#purchase_order_list = PurchaseOrderList.where(PURCHASE_ORDER: params[:ID])
# and then loop through you potentially multiple records in #purchase_order_list
#purchase_order_list.each do |po|
#stockdiary = Stockdiary.create(PRODUCT: po.PRODUCT, UNITS: po.UNITS, PRICEBUY: po.PRICEBUY)
end
or use first:
#stockdiary = Stockdiary.create(PRODUCT: #purchase_order_list.first.PRODUCT, UNITS: #purchase_order_list.first.UNITS, PRICEBUY: #purchase_order_list.first.PRICEBUY)
Usually this means you didn't place accepts_nested_attributes_for in the PurchaseOrder model.
PurchaseOrder
class PurchaseOrder
accepts_nested_attributes_for :purchase_order_list
end

custom attributes in rails

I have a Student model and a method that does some calculations and returns a value
class Student < ActiveRecord::Base
def total_result
#some calculations
return result
end
end
Now in my students controller I would like to do the following
Student.where("total_result > ?", params[:result])
but this brings a PG::UndefinedColumn: ERROR. I am using postgres. How do I achieve this?
You could use:
Student.select { |student| student.total_result > params[:result] }
A word of warning: This will load all students from the database and calculate the value for each of them. This will be slow depending on the number of students in the table.
If you need this more frequently then it would make sense to store/cache the result of the calculation in the database.

Querying or iterating join tables in ActiveRecord/Rails

I have two tables:
Venues
has_many :venue_intel_maps
VenueIntelMap
belongs_to :venue
In the venue_intel_map table there's a column called :tag_label that I want to grab for each particular venue that has a venue_intel_map
In my controller below this returns an array of each venue where then each venue has a venue_id
def show
#venues = Venue.where(parent_venue_id: current_admin.parent_venue_id)
end
So in my views, I can do this for particular venue.
- #venues.each do |venue|
=venue.name
=venue.address
=venue.location
But because I want to get to venue_intel_maps table so I can call a column called :tag_label I wanted to avoided a nested each statement that might look something like this
- #venues.each do |venues|
- venues.venue_intel_maps.each do |intel_maps|
= intel_maps.tag_label
Is there anyway I can clean this up or any suggestions? I was trying to play around with .joins or .selects in active record but didn't know how to successfuly do that so I can somehow put the logic in my Venues model.
EDIT
Would it also be better somehow to define in the controller my venue doing this? In the views I'm going to be pulling things from my venue_intel_maps table so would this serve any advantage?
#venues = Venue.joins(:venue_intel_maps).where(parent_venue_id: current_admin.parent_venue_id)
depending on your Rails version, try:
#venues.venue_intel_maps.pluck(:tag_label)
#venues.venue_intel_maps.map(&:tag_label)
see: http://rubyinrails.com/2014/06/rails-pluck-vs-select-map-collect/
You could preload (Rails 3+) the venue_intel_maps in the controller
def show
#venues = Venue.where(
parent_venue_id: current_admin.parent_venue_id
).preload(:venue_intel_maps)
end
Then in the view, use the iteration you suggested
- #venues.each do |venue|
= venue.name
= venue.address
= venue.location
= venue.venue_intel_maps.each do |intel_maps|
= intel_maps.tag_label

Mass creation and association of habtm

I have 3 models (Genre, Mood, Tempo) each with a has_and_belongs_to_many association with another model (Track). The user can upload an Excel file with info for each track and I want to be able to create the respective records and add the association all at once in my update method.
I'm reading each row from the spreadsheet and creating arrays holding the genres, moods, and tempos that are to be associated with each track, but I'm not sure how to correctly create the association.
Something like:
1.upto #worksheet.last_row_index do |index|
row = #worksheet.row(index)
genres = row[6].split(", ")
genres.each do |g|
Genre.find_or_create_by_name(g) // not sure what to do here exactly
end
end
The Track ID is row[0].
I need to create each Genre if it doesn't exist, and associate that track with each. If the genre does exist, then I just need to create the association. Same for moods and tempos.
Thanks for any assistance.
This seems to do it.
1.upto #worksheet.last_row_index do |index|
row = #worksheet.row(index)
track = Track.find(row[0])
genres = row[6].split(", ")
genres.each do |g|
track.genres << Genre.find_or_create_by_name(g)
end
end

Resources