undefined method `each' for nil:NilClass in update method - ruby-on-rails

I have an Audi model in my ruby on rails application in which there are many fields like model, variant, car image, exterior, interior, brochure etc. When I try to update some attributes(not all), then it gives undefined method `each' for nil:NilClass in exterior and interior image section.
More specifically, the issue is here:
params[:exterior_image].each { |exterior_image| ... }
update method:
def update
respond_to do |format|
#audi_model = AudiModel.find(params[:id])
if #audi_model.update(audi_model_params)
model_exterior_image_names = #audi_model.car_exterior_images.map{|m|m.exterior_image_file_name}
params[:exterior_image].each { |exterior_image|
unless model_exterior_image_names.include?(exterior_image.original_filename)
#audi_model.car_exterior_images.create(exterior_image: exterior_image)
end
}
model_interior_image_names = #audi_model.car_interior_images.map{|m|m.interior_image_file_name}
params[:interior_image].each { |interior_image|
unless model_interior_image_names.include?(interior_image.original_filename)
#audi_model.car_interior_images.create(interior_image: interior_image)
end
}
format.html { redirect_to #audi_model, notice: 'Audi model was successfully updated.' }
format.json { render :show, status: :ok, location: #audi_model }
else
format.html { render :edit }
format.json { render json: #audi_model.errors, status: :unprocessable_entity }
end
end
Request
parameters :
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"3qiq/VNRNk369HEZr0Eb/R5iuhKgGTpJCfOh8ek3nGWLeU+zDNDvEAwJ3SvlLb0h4gVql549d3GnCV9Fa/ZnNA==",
"audi_model"=>{"car_model"=>"TT",
"variant"=>"Diesel",
"introduction"=>"test",
"engine"=>"test",
"video_url"=>"https://www.youtube.com/watch?v=N3x_RZlOmK0",
"brochure_url"=>"http://www.audigurgaon.in/brochure/tt-brochure-2014.pdf"},
"commit"=>"Update Audi model",
"id"=>"19"}

Your params doesn't have :exterior_image key, so it would return nil. You have to check to make sure there params[:exterior_image] is not nil and only then call .each method on it.
params[:exterior_image].each do |exterior_image|
unless model_exterior_image_names.include?(exterior_image.original_filename)
#audi_model.car_exterior_images.create(exterior_image: exterior_image)
end
end if params[:exterior_image]
Alternatively, give it an empty array:
(params[:exterior_image] || []).each do |exterior_image|
unless model_exterior_image_names.include?(exterior_image.original_filename)
#audi_model.car_exterior_images.create(exterior_image: exterior_image)
end
end

Related

Rails 4: Params with a hash

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 => [])

Creating multiple objects of same model in Rails

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.

NoMethodError: undefined method

I am working through Agile Web Development with ruby on rails. While running a test, I get the following:
Error: LineItemsControllerTest#test_should_update_line_item:
NoMethodError: undefined method 'product_id' for nil:NilClass
test/controllers/line_items_controller_test.rb:13:in `block in <class:LineItemsControllerTest>
Here is my test file
require 'test_helper'
class LineItemsControllerTest < ActionController::TestCase
test "should create line_item" do
assert_difference('LineItem.count') do
post :create, product_id: products(:ruby).id
end
assert_redirected_to cart_path(assigns(:line_item).cart)
end
test "should update line_item" do
patch :update, id: #line_item, line_item: { product_id: #line_item.product_id }
assert_redirected_to line_item_path(assigns(:line_item))
end
end
Could someone kindly explain why I get a NoMethodError: undefined method while the book says it should be fine?
Thank you!
Update 1
As per Boltz0r's comment below, here are my create and update methods. I tried comparing what I have versus what is in the book and can't seem to find the problem.
def create
product = Product.find(params[:product_id])
#line_item = #cart.add_product(product.id)
respond_to do |format|
if #line_item.save
format.html { redirect_to #line_item.cart, notice: 'Line item was successfully created.' }
format.json { render :show, status: :created, location: #line_item }
else
format.html { render :new }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #line_item.update(line_item_params)
format.html { redirect_to #line_item, notice: 'Line item was successfully updated.' }
format.json { render :show, status: :ok, location: #line_item }
else
format.html { render :edit }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
I've checked the actual example from the book so will now post the answer so maybe somebody else could see it. If you going to test is update operation you should have something to update first. That's why the test from the book and any other real-life one has setup method to pre-create test item:
setup do
#line_item = line_items(:one)
end
What that error means is that in here:
patch :update, id: (at)line_item, line_item: { product_id: (at)line_item.product_id }
the (at)line_item is nil. so it means you probably have an error either on the create method or maybe in the update method (you are not getting the right line_item)

Ruby on Rails - model validation

I have a problem with simple model validation.
Entering materials without SKU is getting me error message:
NoMethodError in Materials#create undefined method `empty?' for
nil:NilClass
material.rb:
class Material < ActiveRecord::Base
validates :sku, :presence => true
end
materials_controler.rb (create part only):
# POST /materials
# POST /materials.json
def create
#material = Material.new(material_params)
respond_to do |format|
if #material.save
format.html { redirect_to #material, notice: 'Material was successfully created.' }
format.json { render :show, status: :created, location: #material }
else
format.html { render :new }
format.json { render json: #material.errors, status: :unprocessable_entity }
end
end
end
Your #units instance variable is nil in create action. You should set it the same way as you do in new or edit actions after your records fails validation.
Define #units also in your create method

Rails - ActionController::Parameters include controller value with form values

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.

Resources