Rails: Nested Forms and setting nested values - ruby-on-rails

I have created a nested form. I have a model called contract and another called contract_details. In my contract controller I have the following code:
def new
#contract = Contract.new
#contract.customer_id = params[:customer_id]
7.times {
#contract.contract_details.build
#contract.contract_details.del_day = "Sun"
}
end
del_day is a column in my contract_details model but the following line of code is erring out:
#contract.contract_details.del_day = "Sun"
What am I doing wrong? How do I access a column in the nested model from the top controller. Meaning, how do I set the value of a column in the contract_details model when building each row in the contracts controller?

When I re-read, you would only be doing the same thing 7 times if it was an array, so suggest you try the following:
def new
#contract = Contract.new
#contract.customer_id = params[:customer_id]
7.times {
#new_contract_details = #contract.contract_details.build
#new_contract_details.del_day = "Sun"
}
end
The issue would be that at present when you call the following line, there is no indication which of the 'contract_details' objects you are trying to update.
#contract.contract_details.del_day = "Sun"

Related

Adding values to a hash within/over multiple each loops

I have a concept called snapshot which basically stores a snapshot of how data looked at a certain period of time. What I'm building is a method that loops through the snapshots for each events, and builds a small hash outlining the ownership over time for a given shareholder.
def fetch_ownership_over_time(shareholder, captable)
#shareholder = Shareholder.find(shareholder.id)
#captable = Captable.find(captable.id)
#company = #captable.company.id
#ownership_over_time = []
#captable.events.collect(&:snapshot).each do |snapshot|
parsed_snapshot = JSON.parse(snapshot)
#ownership_over_time.push(parsed_snapshot["event"]["name"])
#ownership_over_time.push(parsed_snapshot["event"]["date"])
parsed_snapshot["shareholders"].each do |shareholder|
if shareholder["id"] == #shareholder.id
#ownership_over_time.push(shareholder["ownership_percentage"])
end
end
end
return #ownership_over_time
end
I then call this method in my view which successfully retrieves the correct values however they are not structured in any way:
["Event 1 ", "2018-11-19", "0.666666666666667", "Event 2 ", "2018-11-19", "0.333333333333333", "4th event ", "2018-11-19", "0.315789473684211"]
What I'd like to do now though is construct my hash so that each separate snapshot event contains a name, date and ownership_percentage.
Perhaps something like this:
ownership_over_time = [
{
event_name = "Event 1" #parsed_snapshot["event"]["name"]
event_date = "20180202" #parsed_snapshot["event"]["date"]
ownership_percentage = 0.37 #shareholder["ownership_percentage"]
},
{
event_name = "Event 2" #parsed_snapshot["event"]["name"]
event_date = "20180501" #parsed_snapshot["event"]["date"]
ownership_percentage = 0.60 #shareholder["ownership_percentage"]
}
]
My challenge though is that the ["event"]["name"] an ["event"]["date"] attributes I need to fetch when looping over my snapshots i.e. the first loop (.each do |snapshot|) whereas I get my ownership_percentage when looping over shareholders - the second loop (.each do |shareholder|).
So my question is - how can I build this hash in "two" places so I can return the hash with the 3 attributes?
Appreciative of guidance/help - thank you!
You have to create a new hash for the object and append that hash to the array of objects you are creating.
def fetch_ownership_over_time(shareholder, captable)
#shareholder = Shareholder.find(shareholder.id)
#captable = Captable.find(captable.id)
#company = #captable.company.id
#ownership_over_time = []
#captable.events.collect(&:snapshot).each do |snapshot|
parsed_snapshot = JSON.parse(snapshot)
shareholder = parsed_snapshot['shareholders'].select { |s| s['id'] == #shareholder.id }.first
local_snapshot = {
'event_name' => parsed_snapshot['event']['name'],
'event_date' => parsed_snapshot['event']['date'],
'ownership_percentage' => shareholder.try(:[], "ownership_percentage") || 0
}
#ownership_over_time.push local_snapshot
end
return #ownership_over_time
end
Notice that I changed your second loop to a select. As you currently have it, you risk on pushing two percentages if the id is found twice.
EDIT:
Added functionality to use a default value if no shareholder is found.

rails controller map unknown

In authors_controller.rb, I have this :
def show
a = Author.find(params[:id])
#author = a.map { |e| e.titlecase }
end
I get an error say that map is an undefined method for Author::0x007fec244142a0.
I also tried this :
def show
#author = Author.find(params[:id])
#author.each { |k, v| v.capitalize }
end
How can I apply the method titlecase to each value of Author.find ?
find(params[:id]) returns not array, not enumerator and not Relation class but just instance of your model. You can't use map or each so just apply titlecase to returned object.
def show
#author = Author.find(params[:id])
#author.name = #author.name.titlecase # if you have column 'name'
end
But better move titlecased name to model's method or just use #author.name.titlecase where it's needed.
You can use where and use map operator with it:
def show
#author = Author.where(id: params[:id])
It's ugly but it works. I'm sure there is a better way to do this stuff.
#author.attributes.map do |k,v|
v = #author.__send__(k).capitalize if #author.__send__(k).respond_to?(:capitalize)
end
#author.save
I must say however that I wouldn't recommend doing things this way. Better to capitalize each field in the model
From I understood. You want to capitalize all fields of record Author.find(params[:id]) right?
First, Author.find(params[:id]) will return a record, not array. That means you can't use each or map for it.
To capitalize all fields of a record. Could u try:
def show
author = Author.find(params[:id])
#author = author.attributes.values.map{|field| field.to_s.capitalize}
end
It will return an array of all field values.
UPDATE 1
For better
def show
author = Author.find(params[:id])
#author_info = author.attributes.values.map{|field| field.is_a?(String) ? field.capitalize : field}
end

POST Multiple Row to Database with fill out only one form on RAILS

I'm try to develop one rails application.
When I fill out the form, I'm getting this parameter.
"daysoff"=>{"offdate"=>"06/08/2015, 06/09/2015, 06/10/2015, 06/11/2015, 06/12/2015", "assign_id"=>"3", "user_id"=>"2"}
Here is my index controller,
def index
#people = User.all
#user = User.current
#daysoff = Daysoff.new
end
My table coloumns are offdate (date), user_id (int), :assign_id (int), so i want to post each date for one row and other column values must be same.
How should i write create controller ?
You could do something like
off_dates = params["daysoff"]["offdate"].try(:split,',')
off_dates.each do |off_date|
days_off = Daysoff.new
days_off.offdate = Date.strptime(off_date.strip, "%m/%d/%Y")
days_off.user_id = params["user_id"]
days_off.assign_id = params["assign_id"]
days_off.save!
end

Remove current model instance from AR:Relation

I am creating an instance method on a model which returns instances of the same model. How can I ensure that the instance of the model that the method is being called upon is not part of the output?
My code is like this at the moment:
def other_versions(include_current = true)
if include_current
Coaster.where(order_ridden: order_ridden)
else
#coaster.other_version_count // Need this to exclude the current instance.
end
end
I'm not sure I understood, but would this help?
def other_versions(include_current = true)
query = Coaster.where(order_ridden: order_ridden)
query = query.where("id != ?", id) unless include_current
query
end

Using a method while looping through an array in ruby

I am using ruby-aaws to return Amazon Products and I want to enter them into my DB. I have created a model Amazonproduct and I have created a method get_amazon_data to return an array with all the product information. When i define the specific element in the array ( e.g. to_a[0] ) and then use ruby-aaws item_attributes method, it returns the name I am searching for and saves it to my DB. I am trying to iterate through the array and still have the item_attributes method work. When i don't define the element, i get this error: undefined method `item_attributes' for #Array:0x7f012cae2d68
Here is the code in my controller.
def create
#arr = Amazonproduct.get_amazon_data( :r ).to_a
#arr.each { |name|
#amazonproduct = Amazonproduct.new(params[:amazonproducts])
#amazonproduct.name = #arr.item_attributes.title.to_s
}
EDIT: Code in my model to see if that helps:
class Amazonproduct < ActiveRecord::Base
def self.get_amazon_data(r)
resp = Amazon::AWS.item_search('GourmetFood', { 'Keywords' => 'Coffee Maker' })
items = resp.item_search_response.items.item
end
end
Thanks for any help/advice.
I'm not familiar with the Amazon API, but I do observe that #arr is an array. Arrays do not usually have methods like item_attributes, so you probably lost track of which object was which somewhere in the coding process. It happens ;)
Try moving that .item_attributes call onto the object that supports that method. Maybe amazonproduct.get_amazon_data(:r), before its being turned into an array with to_a, has that method?
It's not quite clear to me what your classes are doing but to use #each, you can do something like
hash = {}
[['name', 'Macbook'], ['price', 1000]].each do |sub_array|
hash[sub_array[0]] = sub_array[1]
end
which gives you a hash like
{ 'name' => 'Macbook', 'price' => 1000 }
This hash may be easier to work with
#product = Product.new
#product.name = hash[:name]
....
EDIT
Try
def create
#arr = Amazonproduct.get_amazon_data( :r ).to_a
#arr.each do |aws_object|
#amazonproduct = Amazonproduct.new(params[:amazonproducts])
#amazonproduct.name = aws_object.item_attributes.title.to_s
end
end

Resources