I want to create multiples objects of a same model in Rails and I'm facing some problems saving them. I already add and remove fields dynamically, but I can't figure out how to save the multiples objects.
I'm receiving the data from my View like this:
Parameters: {
"utf8"=>"✓",
"authenticity_token"=>"0aoRgalvZPKdBJr15EooxNCimh2C6R2RBYi3wTXTpaIwpzb8cNSAH/968932KFscg8eiNPej1x2iYFsaWalVQw==",
"transaction"=>{
"client_id"=>"206",
"invoice_id"=>"1",
"date"=>"07/07/2016",
"value"=>"50",
"description"=>""},
"dates"=>[
"07/08/2016",
"07/09/2016"],
"values"=>[
"49",
"48"],
"commit"=>"Save"}
transaction is the main transaction, dates and values are what difers from the main transaction and the other two transactions.
My create method in TransactionController is like this:
def create
#transaction = Transaction.new(transaction_params)
dates = params['dates']
values = params['values']
if(!dates.nil?)
#transactions_ = []
dates.length.times do |i|
t = Trasanction.create(
client_id: #transaction.client_id,
invoice_id: #transaction.invoice_id,
description: #transaction.description,
date: dates[i],
value: values[i])
#transactions_ << t
end
end
respond_to do |format|
if #transaction.save
#transactions_.each do |t|
t.save
end
format.html { redirect_to #transaction, notice: 'Transaction succefully created.' }
format.json { render :show, status: :created, location: #transaction }
else
format.html { render :new }
format.json { render json: #transaction.errors, status: :unprocessable_entity }
end
end
end
But I'm getting this error:
uninitialized constant TransactionsController::Trasanction
t = Trasanction.create(
Apparently I can't call Transaction.create that way, but I'm almost sure I saw something like that on a tutorial.
I see there is a mistake in your class name. It should be
Transaction.create({})
but, you are referring to it as
Trasanction.create({})
Just change the class name and it should work.
Related
I have a model called Litter that accepts nested attributes for the model Puppy. When submitting an update to a litter I want to modify all the nested puppies so it adds a new attribute (breed_id). This is because the breed_id can be inferred from the litter and I don't want the user to specify it for every puppy. Here's what my controller looks like:
def update
litter_params[:puppies_attributes].each do |puppy|
puppy[1][:breed_id] = litter_params[:breed_id]
end
respond_to do |format|
if #litter.update(litter_params)
format.html { redirect_to litters_url, notice: "Litter was successfully updated." }
format.json { render :show, status: :ok, location: #litter }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #litter.errors, status: :unprocessable_entity }
end
end
end
However, for some reason the puppy nested attributes continue to not include the new attribute (breed_id):
Parameters: {"authenticity_token"=>"[FILTERED]", "litter"=>{"dog_ids"=>["", "3", "10"], "breed_id"=>"115", "puppies_attributes"=>{"0"=>{"_destroy"=>"false", "name"=>"Oscar", "id"=>"31"}, "1623432054943"=>{"_destroy"=>"false", "name"=>"James"}}}, "commit"=>"Update Litter", "id"=>"11"}
Any idea how I can add this attribute to the nested models?
This is my litter_params by the way:
def litter_params
params.require(:litter).permit(:breed_id, :breeder_id, dog_ids: [], puppies_attributes: [:_destroy, :id, :name])
end
I have a model called event which attributes are:
string "name"
string "location"
string "lecturer"
date "start_time"
date "end_time"`
I want to take data from icalendar type file and create event instances. How should I do this ? I tried to do a method in events_controller.rb:
def new_method
#ievent_file = File.open("calendar2.ics")
#ievents = Icalendar::Event.parse(#ievent_file)
#ievent = #ievents.first
#ievent = Event.new(name:#ievent.summary,location:#ievent.location, lecturer:#ievent.description, start_time:#ievent.dtstart, end_time:#ievent.dtend)
end
But then what I should do with it ? Should I call this function in view or maybe should I take this code to method called create which looks like this:
def create
#event = Event.new(event_params)
respond_to do |format|
if #event.save
format.html { redirect_to #event, notice: 'Event was successfully created.' }
format.json { render :show, status: :created, location: #event }
else
format.html { render :new }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
end
my understanding calendar2.ics have many records, if you want to loop through all the event inside calendar2.ics and save it to your event table (import ics file to event table)
below are sample steps, inside your routes file create one method
resources :events do
collection {
get :transfer_data_from_ics
}
end
inside your events_controller you create 2 methods
def transfer_data_from_ics
# get data from ics
#ievent_file = File.open("calendar2.ics")
#ievents = Icalendar::Event.parse(#ievent_file)
# loop through
#ievents.each do |i_event|
Event.create(
name: i_event.summary,
location: i_event.location,
lecturer: i_event.description,
start_time: i_event.dtstart,
end_time: i_event.dtend)
end
# route back to events list
redirect_to events_path
end
to get the method called you can create menu / button with link_to as follow:
<%= link_to "Transfer data", transfer_data_from_ics_events_path %>
I have a form that passes an array to my controller in the params and it keeps causing an ActiveModel::ForbiddenAttributesError. My create function calls out to another function to fix these array params and combine the parts into a string, but I think it's too late at that point.
Params
{ "remote"=>
{ "name"=>"",
"start_date"=>"9/27/2016",
"email"=>"",
"allergies"=>["Peanuts", "Soy Protein", "Dairy", ""],
}
}
Controller
def create
new_params = fix_params(params, ["allergies"])
remote_params = new_params["remote"]
#remote = Remote.new(remote_params)
respond_to do |format|
if #remote.save
format.html { redirect_to root_path, notice: 'Remote was successfully created.' }
format.json { render :show, status: :created, location: #remote }
else
format.html { render :new }
format.json { render json: #remote.errors, status: :unprocessable_entity }
end
end
end
def fix_params(params, fields)
fields.each do |field|
to_change = params[:remote][field]
new_param = to_change.join(", ").strip()
params[:remote][field] = new_param || ""
end
return params
end
Maybe there is a better way to pass these variables?
The error was occurring due to the fact that there were unpermitted parameters because I never explicitly stated that there will be array's passed in the params.
I modified my strong parameters to include params.require(:remote).permit(:name, :start_date, :email, :allergies => [])
I have a session variable (user_id) that I'd like to include as a foreign key on a record the user is inserting. I have the form values all coming through the form submit to my controller's entity.update(params) method without a problem using the default params definition. That code looks like
def brand_params
#brand_params = params.require(:brand).permit(:name, :brand_type, :profile_id)
end
The update method looks like
if #brand.update(brand_params)
format.html { redirect_to #brand, notice: 'Widget was successfully updated.' }
format.json { render :show, status: :ok, location: #brand }
else
format.html { render :edit }
format.json { render json: #brand.errors, status: :unprocessable_entity }
end
Now I'd like to append the :profile_id session variable to the #brand_params and following other threads here, I've tried a setter method:
def set_brand_params(key, val)
if #brand_params != nil
#brand_params[key] = val
end
end
However, calling this, #brand_params is always nil. Trying to directly add to the brand_params hash doesn't work because it's a better method. If there's a better way to meet this (I'd assume common) use case, I'm all ears! Otherwise, I'd like to know why the var is always nil though in this context, at least the brand_params method sees it as defined and with value. I got this solution in Adding a value to ActionController::Parameters on the server side
Here is the update method as requested:
def update
puts "update"
set_brand_params("profile_id", session[:prof])
respond_to do |format|
if #brand.update(brand_params)
format.html { redirect_to #brand, notice: 'Widget was successfully updated.' }
format.json { render :show, status: :ok, location: #brand }
else
format.html { render :edit }
format.json { render json: #brand.errors, status: :unprocessable_entity }
end
end
end
I'm not agree with merge your data with the params. Because you must permit only the fields you expect your user update. In this case you don't want the user update profile_id on brands, and that is a security best practice.
Then brand_params must be:
def brand_params
#brand_params = params.require(:brand).permit(:name, :brand_type)
end
Your method update may look by this:
def update
#brand = Brand.find(params[:id])
#brand.assign_attributes(profile_id: session[:prof])
respond_to do |format|
if #barnd.update(brand_params)
format.html { redirect_to #brand, notice: 'Widget was successfully updated.'}
format.json { render :show, status: :ok, location: #brand }
else
format.html { render :edit }
format.json { render json: #brand.errors, status: :unprocessable_entity }
end
end
end
You don't need the method set_brand_params at all.
If this don't do the trick, please publish the entry controller, and I hope we find the issue.
edit: add respond_to.
I'd like the creation of a Window to generate a number of Timeslots that belong to it. It's pretty easy to take an integer from a form object and create that many timeslots, but I can't figure out how to grab the window ID to tell the timeslots who they belong to.
def create
#window = Window.new(window_params)
#window.capacity.times do
if Timeslot.last
then
#newID = Timeslot.last.id += 1
else
#newID = 1
end
#timeslot = Timeslot.new({id: #newID})
#timeslot.created_at = Time.now
#timeslot.window_id = #window.id
#timeslot.save
end
respond_to do |format|
if #window.save
format.html { redirect_to #window, notice: 'Window was successfully created.' }
format.json { render :show, status: :created, location: #window }
else
format.html { render :new }
format.json { render json: #window.errors, status: :unprocessable_entity }
end
end
end
If anyone can point me to a more elegant way to find a new Timeslot ID, I'd appreciate it too.
#window will not have an ID until after it is saved to the database. Therfore, create timeslots after the record is saved. I extracted timeslot creation to its own private method that gets called after save.
def create
#window = Window.new(window_params)
respond_to do |format|
if #window.save
create_timeslots # <-- timeslot creation performed after save
format.html { redirect_to #window, notice: 'Window was successfully created.' }
format.json { render :show, status: :created, location: #window }
else
format.html { render :new }
format.json { render json: #window.errors, status: :unprocessable_entity }
end
end
end
private
def create_timeslots
#window.capacity.times do
Timeslot.create({window_id: #window.id})
end
end
I removed the code which sets timeslot ID and creation time because ActiveRecord does it already. No need to reinvent the wheel.