I am fairly new to Rails and I have these two models...
class Invoice < ActiveRecord::Base
has_many :items
accepts_nested_attributes_for :items
...
end
class Item < ActiveRecord::Base
belongs_to :invoice
def self.total
price * quantity
end
...
end
... and a nested (!) form that creates new invoice records and their associated items.
However, I find it very difficult to perform calculations on these items. For example next to each item I would like to put the total for this item using the total method above.
Unfortunately, it's not working. In my form I put this next to each item:
<%= #invoice.items.amount %>
which is derived from my controller:
def new
#invoice = Invoice.new
3.times {#invoice.items.build}
end
It keeps throwing an error saying undefined local variable or method price
What am I missing here??
Thanks for any help.
You have created a class method on Item, when I think what you want is an instance method.
class Item < ActiveRecord::Base
belongs_to :invoice
def total
price * quantity
end
...
end
which you can call on an individual item #item.total or, if you do you the total of all the items, then you'd need to do something like this:
class Item < ActiveRecord::Base
belongs_to :invoice
def self.total
all.collect { |item| item.price * item.quantity }
end
...
end
#invoice.items.total
Hope that helps.
Related
Student has_many Lessons
Lesson belongs_to Prices
How can I show the sum of all Prices that Student has in show action of the StudentsController?
As #mgidea already correctly said:
You want to create a has_many :through relationship in your Student model first and then you want to convert the prices of your Student into an Array with #to_a and then create the sum of your price_attribute.
Add the following to your Student model:
class Student < ActiveRecord::Base
has_many :lessons
has_many :prices, through: :lessons # <= Add this here
end
Your show action could than look like:
class StudentsController < ApplicationController
def show
#student = Student.find(params[:id]
#sum = #student.prices.to_a.sum(&:price)
# Equivalent to:
# #sum = #student.prices.to_a.sum { |p| return p.price }
end
end
Than you could use the instance variable #sum in your view.
Hope this helps!
Happy coding :)
Addin a query of sum in controller does it.
Answer: https://github.com/yshmarov/myclass101/commit/9a998da2af07caee76948d2941ad006029a0f47a
As a beginner I thought that it would be easy to store current user session ID into another table as I managed to get the user ID into Line_Items table however I believe that I have not understood the basic principle of storing one primary key into another table as a foreign key which in my case is trying to store session User_ID into Carts table as a cart belongs to a user and user has many cart. Any code or any helpful link regarding this question will be greatly appreciated. Following are my models. Please let me know if any other code is needed for assistance. Thanks:
class User < ActiveRecord::Base
attr_accessible :email, :first_name, :last_name, :password, :role, :subscriber, :name
has_many :line_item
has_many :cart
class NotAuthorized < StandardError; end
end
Cart.rb:
class Cart < ActiveRecord::Base
attr_accessible :user_id
has_many :line_items, dependent: :destroy
belongs_to :user
def add_phone(phone, current_user = nil)
current_item = line_items.find_or_initialize_by_phone_id(phone.id)
current_item.increment!(:quantity)
current_item.phone.decrement!(:stock)
current_item.user = current_user
current_item.phone.save
current_item
end
# returns true if stock level is greater than zero
def can_add(phone)
phone.stock > 0
end
# returns the total number of items in a cart
def number_of_items
total = 0
line_items.each do |item|
total += item.quantity
end
total
end
def empty?
number_of_items == 0
end
def grand_total
grand_total = 0
line_items.each do |item|
grand_total += item.quantity * item.phone.price
end
grand_total
end
end
You have an error in your relationship declaration.. they should be plural, try that and see if it helps, also you should have an user_id on your carts & line items models.
has_many :line_items
has_many :carts
In User model
has_many :line_items
has_many :carts
Also in line Item and Cart model, you can mention:
belongs_to :user
We can mentioned it using :foreign_key as well given below:
belongs_to :user, foreign_key: "user_id"
Hope it will be helpful for you..
For getting session ID or for saving the records in your cart controller or line items controller
For LineItem
#In create action
#line_item = current_user.line_items.build(params[:user])
# or
#line_item.user = current_user
For Cart
#In create action
#cart = current_user.carts.build(params[:user])
# or
#cart.user = current_user
For getting user id in your controller for finding related line_items and cart you can simply get it by current_user.id
In controllers or views for session id you can use as below
session['session_id']
Thanks.
I think I'm either missing something really simple or something really obscure. Hoping someone can spot it for me or explain my muppetry.
Ok, So there are two models, Basket and BasketItem.
I've set Basket to accept_nested_attributes :basket_items with the intention of using fields_for in an edit view of Basket.
However when run up it still screams that
Error: Can't mass-assign protected attributes: basket_items_attributes
For the sake of this question I've boiled down to the same issue if I do a manual basket.update_attributes in the console with just one or two basket_item attributes. So I know it's a model issue, not a view or controller issue.
e.g.:
basket.update_attributes("basket_items_attributes"=>[{"qty"=>"1", "id"=>"29"}, {"qty"=>"7", "id"=>"30"}])
or similarly with a hash more like fields_for makes
basket.update_attributes( "basket_items_attributes"=>{
"0"=>{"qty"=>"1", "id"=>"29"},
"1"=>{"qty"=>"7", "id"=>"30"}
})
I've ensured that the associates in defined before the accepts_nested_attibutes_for, that the child model has the appropriate attributes accesable too, tried removing additional attributes for the nested data, lots of fiddling to no avail.
basket.rb
class Basket < ActiveRecord::Base
has_many :basket_items
attr_accessible :user_id
accepts_nested_attributes_for :basket_items
belongs_to :user
def total
total = 0
basket_items.each do |line_item|
total += line_item.total
end
return total
end
# Add new Variant or increment existing Item with new Quantity
def add_variant(variant_id = nil, qty = 0)
variant = Variant.find(variant_id)
# Find if already listed
basket_item = basket_items.find(:first, :conditions => {:variant_id => variant.id})
if (basket_item.nil?) then
basket_item = basket_items.new(:variant => variant, :qty => qty)
else
basket_item.qty += qty
end
basket_item.save
end
end
basket_item.rb
class BasketItem < ActiveRecord::Base
belongs_to :basket
belongs_to :variant
attr_accessible :id, :qty, :variant, :basket_id
def price
variant.price
end
def sku
return variant.sku
end
def description
variant.short_description
end
def total
price * qty
end
end
As the error says, you just need to add basket_items_attributes to your list of accepted attributes.
So you'd have
attr_accessible :user_id, :basket_items_attributes
at the top of your basket.rb file
I have a form for creating a new invoice with many items.
class Invoice < ActiveRecord::Base
attr_accessible :project_id, :number, :date, :recipient, :items_attributes
accepts_nested_attributes_for :items
end
Now when I instantiate a new invoice and a set of containing items, I want these items to know something about the invoice they belong to even before they are saved, so I can do something like this in my Item model:
class Item < ActiveRecord::Base
belongs_to :invoice
after_initialize :set_hourly_rate
private
def set_hourly_rate
if new_record?
self.price ||= invoice.project.hourly_rate
end
end
end
Right now, my code fails because the child (item) doesn't know anything about its parent (invoice) during instantiation. Only after saving the invoice (and thus its nested items), it all works out. But I want to set a default value on each new item even before it gets saved.
How can this be done?
Thanks for any help.
You can add a callback on the invoice association, as follows:
class Invoice < ActiveRecord::Base
# Code
belongs_to :project
has_many :items, :after_add => :set_item_price
private
def set_item_price(item)
item.price = project.hourly_rate
end
end
Once you have your invoice object, you can create children records with the .items.build method (docs here)
items created through this method should have a reference to the invoice
Though, I think they will have the reference only if the Invoice has been persisted (not really sure about that.)
Okay, what I've got is two models...
Jiraissue:
class Jiraissue < ActiveRecord::Base
# JIRA uses a singular table name for this model
set_table_name 'jiraissue'
has_one :severity
end
Severity:
class Severity < ActiveRecord::Base
belongs_to :jiraissue
end
What I'm trying to do is get a count of all Jiraissues for which jiraissue.severity = "S1"
Now it turns out that the jiraissue table has a column for priority so I can pull this trick in the model...
Jiraissue:
class Jiraissue < ActiveRecord::Base
# JIRA uses a singular table name for this model
set_table_name 'jiraissue'
has_one :severity
def self.count_priority(priority)
where("PRIORITY = ?",priority).count()
end
end
And then in the view do something like...
<%= (1..4).map {
|priority| Jiraissue.biit.bugs.recent.count_priority(priority)
}.inspect %>
How do I do something similar for Jiraissue to get a count_severity method?
This just doesn't work (nor would I expect it to)...
def self.count_severity(severity)
where("severity = ?",severity).count()
end
But I'm totally confused.
Jiraissue.joins(:severities).where(:severities => {:severity => "S1"}).count
model
def self.count_priority(priority)
where("PRIORITY = ?",priority).size
end
controller
def index
#jiraissues = Jiraissue.count_priority('S1')
end
Doesn't it work?