Rails: Object saving in console but not within app - ruby-on-rails

I know this must be a dumb error somewhere, but I've been going in circles trying to figure out why my objects only save within the console, and not in the app itself.
Anyone have an idea?
Here's the code:
Controller:
class JobsController < ApplicationController
def index
#jobs = Job.all
end
def new
#job = Job.new
end
def create
#job = Job.new(job_params)
if #job.save
redirect_to jobs_path, flash: { notice: "You've successfully created a job." }
else
redirect_to new_job_path, flash: { alert: #job.errors.messages }
end
end
def edit
#job = Job.find(params[:id])
end
def update
#job = Job.find(params[:id])
if #job.update
redirect_to jobs_path, notice: "You've updated a job."
else
redirect_to edit_job_path, alert: #job.errors.messages
end
end
def destroy
#job = Job.find(params[:id])
if #job.destroy
redirect_to jobs_path, notice: "You've deleted a job."
else
redirect_to jobs_path, alert: #job.errors.messages
end
end
private
def job_params
params.require(:job).permit(:poster, :category, :location, :status)
end
end
And the view:
<h1>Create job</h1>
<form class="form">
<%= form_for #job do |f| %>
<%= f.text_field :poster, placeholder: "Poster", onclick: "placeholder = ''", onblur: "placeholder = 'Poster'", autofocus: true, class: "form-group" %><br>
<%= f.text_field :category, placeholder: "Category", onclick: "placeholder = ''", onblur: "placeholder = 'Category'", class: "form-group" %><br>
<%= f.text_field :location, placeholder: "Location", onclick: "placeholder = ''", onblur: "placeholder = 'Location'", class: "form-group" %><br>
<%= f.select :status, ['New', 'Pending', 'Complete'],placeholder: "Status", onclick: "placeholder = ''", onblur: "placeholder = 'Status'", class: "form-group" %><br><br>
<%= f.submit "Submit", class: "btn btn-secondary" %>
<% end %>
</div>
And the log:
Started GET "/jobs/new?utf8=%E2%9C%93&authenticity_token=FStlZTVRMKg%2Bw3Zkw5%2FdpP1w5I%2Fl4vxlQPwAGKqRjIM704p6vXWXEe9z4GmdoB4FJirP6AzUJRkCPEcEwmVNjQ%3D%3D&job%5Bposter%5D=jill&job%5Bcategory%5D=jill&job%5Blocation%5D=jill&job%5Bstatus%5D=New&commit=Submit" for ::1 at 2017-04-16 15:16:08 -0400
Processing by JobsController#new as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"FStlZTVRMKg+w3Zkw5/dpP1w5I/l4vxlQPwAGKqRjIM704p6vXWXEe9z4GmdoB4FJirP6AzUJRkCPEcEwmVNjQ==", "job"=>{"poster"=>"jill", "category"=>"jill", "location"=>"jill", "status"=>"New"}, "commit"=>"Submit"}
Rendered jobs/new.html.erb within layouts/application (0.8ms)
Completed 200 OK in 13ms (Views: 12.1ms | ActiveRecord: 0.0ms)

This line is breaking your form
<form class="form">
You can't have nested forms in HTML. So <form> from your form_for definition is not interpreted as it should.
Also, there's a dangling </div>.

Related

Ruby 2.7.0 on Rails 6.1, 2 separate post forms one view

hope your having a wonderful day drinking some coffee and responding to some forms.
Problem:
As my title states, I am trying to create 2 forms on one view. I am new to ruby on rails.
My controller functions:
Controller name is border_rotation:
def create
if params[:export_submit]
#border_rotation_export = BorderRotationExport.new(border_rotation_export_params)
respond_to do |format|
if #border_rotation_export.save
flash[:success] = "Export successfully created"
format.html { render :new }
else
flash[:error] = "Export was not created."
end
end
else
#border_rotation_import = BorderRotationImport.new(border_rotation_import_params)
respond_to do |format|
if #border_rotation_import.save
flash[:success] = "Export successfully created"
format.html { render :new }
else
flash[:error] = "Export was not created."
end
end
end
end
def new
#border_rotation_export = BorderRotationExport.new
#border_rotation_import = BorderRotationImport.new
end
private
def border_rotation_export_params
params.require(:border_rotation_export).permit(:exporter_name,:vehicle_color,:rot_num,:current_date,:current_time,:goods_description,:license_num,:entry)
end
def border_rotation_import_params
params.require(:border_rotation_import).permit(:importer_name,:vehicle_color,:rot_num,:current_date,:current_time,:goods_description,:license_num,:entry)
end
My new View form:
It has 2 forms and is enclosed in bootstrap tabs
<%= form_for #border_rotation_export, url: rotation_create_path, method: :post do |f|%>
<lable>Importer Name: </lable><%= f.text_field :importer_name, class: "form-control", placeholder: "Importer Name"%>
<lable>Vehicle Color: </lable><%= f.text_field :vehicle_color, class: "form-control", placeholder: "Vehicle Color"%>
**its fields**
<% end %>
and
<%= form_for #border_rotation_import, url: rotation_create_path, method: :post do |f|%>
<lable>Exporter Name: </lable><%= f.text_field :exporter_name, class: "form-control", placeholder: "Exporter Name"%>
<lable>Vehicle Color: </lable><%= f.text_field :vehicle_color, class: "form-control", placeholder: "Vehicle Color"%>
**its fields**
<% end %>
The error in my new.html.rb
First argument in form cannot contain nil or be empty
Displays this in red highlighted
<%= form_for #border_rotation_export, url: rotation_create_path, method: :post do |f|%>
My guess is that it submits both forms but only has the parameters for one form with the input data. Once I submit, it saves to the database but it gives me the error
**Routes **
get 'rotation/create', to: 'border_rotation#create'
post 'rotation/create', to: 'border_rotation#create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"Cu52CIDgrY0b7Yk6edkd7+RTl5yR4qSEqPPrqWtM0nIQVDvw7eYDF36zduJPLjI+vVNqCfgtLcMDUEkW6qDOdQ==",
"border_rotation_import"=>
{"importer_name"=>"john",
"vehicle_color"=>"red",
"rot_num"=>"11sssfeeea",
"current_date"=>"2021-09-22",
"current_time"=>"09:37",
"goods_description"=>"yogurt",
"license_num"=>"c-11223",
"entry"=>"c1223"},
"import_submit"=>"Submit"}
Thank you in advance
You can setup the controller with a lot less redundancy:
# config/routes.rb
resources :rotations, only: [:new, :create]
class BorderRotationsController < ApplicationController
# GET /rotations/new
def new
populate_forms
end
# POST /rotations
def create
resource = model_class.new(create_params)
set_ivar(resource) # sets #border_rotation_export or #border_rotation_import
if resource.save
flash[:success] = "#{humanized} successfully created"
redirect_to action: :new
else
populate_forms
flash[:error] = "#{humanized} could not be created - please try again."
render :new
end
end
private
# gets the model class via params[:subtype]
def model_class
#model_class ||= begin do
if params[:border_rotation_export].present?
BorderRotationExport
else
BorderRotationImport
end
end
end
def humanized
model_class == BorderRotationExport ? 'Export' : 'Import'
end
def set_ivar(value)
instance_variable_set(
"##{param_key}",
value
) ​
​end
# just sets up the instance variables for the form
def populate_forms
#border_rotation_export ||= BorderRotationExport.new
#border_rotation_import ||= BorderRotationImport.new
end
# border_rotation_export or border_rotation_import
def param_key
model_class.model_name.param_key
end
def create_params
require(param_key).permit(
:exporter_name, :vehicle_color, :rot_num,
:current_date,:current_time, :goods_description,
:license_num, :entry
)
end
And then use partials so that you can resuse the same form:
# app/views/border_rotations/new.html.erb
<%= render partial: 'form',
locals: { border_rotation: #border_rotation_export } %>
<%= render partial: 'form',
locals: { border_rotation: #border_rotation_import } %>
# app/views/border_rotations/new.html.erb
<%= form_with model: border_rotation, url: rotations_path do |f| %>
<div class="field">
<%= f.label :importer_name %>
<%= f.text_field :importer_name, class: "form-control" %>
</div>
<div class="field">
<%= f.label :importer_name %>
<%= f.text_field :importer_name, class: "form-control" %>
</div>
# ...
<% end %>
If the requirements diverge use two separate routes/controllers and inheritance instead of blooming out in tons of new code paths.

Why does simple form not show validation error messages in Rails?

The :new view when redirected if validations are not matched and where I'd like to see the error messages:
<%= simple_form_for ([ #recipe, #recipe.comments.build]), class:"comment-form" do |f| %>
<%= f.error_notification %>
<%= f.object.errors.full_messages.join(", ") if f.object.errors.any? %>
<%= f.input :name, label: false, placeholder: "Your name", input_html: { value: #comment.name } %>
<%= f.input :comment, label: false, placeholder: "Tell us about your experience", input_html: { value: #comment.comment } %>
<%= f.submit "Submit", class: "btn-comment-submit" %>
<% end %>
This is my controller:
def new
#recipe = Recipe.find(params[:recipe_id])
#comment = Comment.new
#comment = #recipe.comments.build
end
def create
#comment = Comment.new(comment_params)
#recipe = Recipe.find(params[:recipe_id])
#comment.recipe = #recipe
if #comment.save
redirect_to recipe_path(#recipe)
else
render :new
end
end
You're not binding the #comment instance you have created in your controller to the form. Instead #recipe.comments.build always creates a new instance of Comment.
You can set the model with a conditional:
<%= simple_form_for([#recipe, #comment || #recipe.comments.build]) do |form| %>
<%= f.error_notification %>
<%= f.object.errors.full_messages.join(", ") if f.object.errors.any? %>
<%= f.input :name, label: false, placeholder: "Your name" %>
<%= f.input :comment, label: false, placeholder: "Tell us about your experience" %>
<%= f.submit "Submit", class: "btn-comment-submit" %>
<% end %>
Note that you don't need to set the values for the inputs. The form builder will do that for you. Thats kind of the whole point of it.
Or you can preferably ensure that you're setting #comment in the controller to keep the view as simple as possible:
class RecipiesController < ApplicationController
before_action :set_recipe
# ...
def show
#comment = #recipe.comments.new
end
# ...
end
<%= simple_form_for([#recipe, #comment]) do |form| %>
# ...
<% end %>
And you can clean up your create action and just create the comment off the recipe:
def create
#recipe = Recipe.find(params[:recipe_id])
#comment = #recipe.comments.new(comment_params)
if #comment.save
redirect_to #recipe
else
render :new
end
end

Ruby on Rails 5: Can't Save Record, Unpermitted Parameter for Has Many Through Record

Ruby on Rails 5, Simple Form
Product has many Specifications through ProductSpecs
in Product#Edit, I want to add new Specifications.
if Specifications.save successful, rerender Product. It rerenders products and flashes "success", but the new specification does not persist.
The log indicates unpermitted parameters-- not sure how to correct my product_parameters. I have tried { product_specs => [] } to no avail.
Any help would be greatly appreciated!
Log:
Started PATCH "/products/2" for 127.0.0.1 at 2019-03-07 14:44:24 +0800
Processing by ProductsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"f/wU9o1Fi8jXlTDCiJF93xMXFlaRH6sKx9+lNyg4ZGthVGkhPMrLwES/bEgeeHTHXdXaoolj67FOnGqqULtysg==", "product"=>{"name"=>"Notebooks", "description"=>"Handheld military and medical devices are built to operate in a variety of environments and also built to last.asdfasdfasdf", "category_id"=>"1", "product_spec"=>{"specification"=>{"name"=>"COLD", "low_value"=>"1", "high_value"=>"22", "unit"=>"volts"}}}, "commit"=>"Add New Spec", "id"=>"2"}
Product Load (0.1ms) SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
Setting the product: Notebooks
#<Product id: 2, name: "Notebooks", description: "Handheld military and medical devices are built to...", picture: nil, created_at: "2019-02-20 06:43:20", updated_at: "2019-03-07 05:53:37", iconblack: "icons/products/icon_IPC_black.png", iconwhite: nil, iconyellow: nil, category_id: 1>Unpermitted parameter: product_spec
(0.1ms) begin transaction
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
(0.1ms) commit transaction
SUPPOSEDLY UPDATING
Unpermitted parameter: product_spec
product parameters: <ActionController::Parameters {"name"=>"Notebooks", "description"=>"Handheld military and medical devices are built to operate in a variety of environments and also built to last.asdfasdfasdf", "category_id"=>"1"} permitted: true>Redirected to http://localhost:3000/products/2
Completed 302 Found in 7ms (ActiveRecord: 0.5ms)
Started GET "/products/2" for 127.0.0.1 at 2019-03-07 14:44:24 +0800
Processing by ProductsController#show as HTML
Products Controller:
class ProductsController < ApplicationController
# before_action :set_category, only: [:new, :create]
before_action :set_product, only: [:edit, :show, :update, :destroy]
def index
#products = Product.all
#categories = Category.all
#message = Message.new
#message.build_company
end
def new
#product = Product.new
#categories = Category.all
#message = Message.new
#message.build_company
#product.specifications.build
# setting product stuff for testing
#product.picture = "products/IPC_tablet.png"
#product.iconblack = "icons/products/icon_IPC_black.png"
end
def create
#message = Message.new
#message.build_company
#categories = Category.all
#product = Product.new(product_parameters)
#product.category_id = product_parameters[:category_id]
#product_spec = ProductSpec.new
#new_spec= Specification.new
if #product.save!
flash[:success] = "You have saved the #{#product.name} product"
redirect_to product_path(#product)
else
flash.now[:error] = "Product was not saved"
render "new"
end
end
def show
#product = Product.find(params[:id])
#categories = Category.all
#message = Message.new
#message.build_company
#product_specs = #product.product_specs
end
def edit
#message = Message.new
#message.build_company
#categories = Category.all
# To create a new specification through product spec
#product_spec = ProductSpec.new
#new_spec= Specification.new
#product_spec.product = #product
#product_spec.specification = #new_spec
end
def update
# puts "in update product, product parameters: #{product_parameters}"
# puts product_parameters
if #product.update(product_parameters)
flash[:success] = "You have updated the #{#product.name} product"
puts "SUPPOSEDLY UPDATING"
print "product parameters: #{product_parameters.inspect}"
redirect_to product_path(#product)
else
# puts "SUPPOSEDLY NOT UPDATING"
flash.now[:error] = "You have not updated #{#product.name}"
render :edit
end
end
private
def build_company
#message.build_company
end
def set_product
#product = Product.find(params[:id])
puts "Setting the product: #{#product.name}"
print #product.inspect
end
def find_category
#category = Category.find(params[:category_id])
end
def product_parameters
params.require(:product).permit(
:id,
:name,
:description,
:picture,
:category_id,
category: [
:id
],
product_specs: [
{:specification => [] } ]
)
end
end
Product Specs Controller:
class ProductSpecsController < ApplicationController
before_action :find_product, only: [:new, :create, :destroy, :set_product_spec]
before_action :set_product_spec, only: [:destroy, :show]
def new
#product_spec = ProductSpec.new(:product_id => params[:product_id])
end
def create
end
def destroy
#product = Product.find(params[:product_id])
if #product_spec.destroy
flash[:success] = "Product Specification Deleted"
redirect_to product_path(#product.id)
else
flash[:error] = "Oops! Something went wrong"
redirect_to product_path
end
end
private
def find_product
#product = Product.find(params[:product_id])
end
def set_specification
end
def set_product_spec
#product_spec = ProductSpec.find_by(params[:product_id])
end
end
Specifications Controller:
class SpecificationsController < ApplicationController
before_action :set_specification, only: [:edit, :show, :update, :destroy]
def new
end
def create
end
def destroy
end
private
def set_specification
#specification = Specification.find(params[:id])
end
end
Products#Edit Form/View:
<%= simple_form_for #product do |product| %>
<h4 class="product_name">
<%= product.input :name, placeholder: "Product Name" %>
</h4>
<div class="product_picture">
<%= image_tag("products/IPC_tablet.png") %>
</div>
<div class="product_description">
<strong>Description</strong>
<p class="font-size-12">
<%= product.input :description, label: false %>
</p>
<%= product.association :category, prompt: "Select Category" %>
</div>
<div class="product_specifications">
<strong>Specifications</strong>
<!-- RENDER THRU PRODUCT SPECS, EACH EXISTING SPECIFICATION -->
<% if #product_specs %>
<%= product.simple_fields_for :product_specs do |ps| %>
<%= ps.simple_fields_for :specification do |spec| %>
<div class="add_specification">
<div class="specification_fields">
<%= spec.input :name, label: false, input_html: { class: 'spec_input_name' }, placeholder: "Spec" %>
<%= spec.input :low_value, input_html: { class: 'spec_input_values' }, label: false, placeholder:"Lowest Value" %>
<%= spec.input :high_value, input_html: { class: 'spec_input_values' }, label: false, placeholder: "Highest Value" %>
<%= spec.input :unit, label: false, input_html: { class: 'spec_input_values' }, placeholder:"Unit" %>
<%= spec.button :submit, "Save Spec" %>
</div>
</div>
<% end %>
<% end %>
<div>
<strong>Add A New Specification</strong>
</div>
<% end %>
<!-- - - - - - ADD A NEW SPECIFICATION -->
<%= product.simple_fields_for #product_spec do |newps| %>
<%= newps.simple_fields_for #new_spec do |newspec| %>
<div class="add_specification">
<div class="specification_fields">
<%= newspec.input :name, label: false, input_html: { class: 'spec_input_name' }, placeholder: "Spec Name" %>
<%= newspec.input :low_value, label: false, input_html: { class: 'spec_input_values' }, placeholder: "Lowest Value" %>
<%= newspec.input :high_value, label: false, input_html: { class: 'spec_input_values' }, placeholder: "Highest Value" %>
<%= newspec.input :unit, label: false, input_html: { class: 'spec_input_values' }, placeholder: "Unit" %>
<%= newspec.button :submit, "Add New Spec" %>
<% end %>
</div>
<% end %>
</div>
<div class="product_admin_actions">
<%= product.button :submit, "Save This Product" %>
</div>
<% end %>
I think the problem about understanding how accepts_nested_attributes_for works in Rails. I'll try to explain it clearly.
the relation between the models also another important part. If we accept the realtion like: Product -> ProductSpec -> Specification solution must be like this.
# models/product.rb
class Product < ApplicationRecord
has_many :product_specs
accepts_nested_attributes_for :product_specs
end
# models/product_spec.rb
class ProductSpec < ApplicationRecord
has_many :specifications
accepts_nested_attributes_for :specifications
end
# controllers/products_controller.rb
class ProductsController < ApplicationController
...
def create
#proudct = Product.create(product_params)
end
private
def product_params
params.require(:product).permit(
:id,
:name,
:description,
:picture,
:category_id,
product_specs_attributes: [:id,
specifications_attributes: [:id, :name, :low_value, :high_value]
])
end
end
Your view fields looks correct.

Rails duplicates records when using ajax to submit the form

My form needs to customize before submitting to the rails. SO, I use ajax to submit the form, but every time, rails doubles records. Anyone has any idea how it happens.
my controller here:
def create
#school_current = School.find_by_id(params[:school_id])
#quiz = Quiz.new(params[:quiz])
#quiz.from_params(params)
questions = params[:quiz][:questions_attributes]
questions.each do |index, question|
#quiz.questions.build(question)
end
respond_to do |format|
if #quiz.save
format.html { render nothing: true }
else
format.html { render action: "new" }
end
end
end
def from_params(params)
self.name = params[:quiz][:name]
self.school_id = params[:school_id]
self.description = params[:quiz][:description]
end
form:
<div id="quizzes">
<%= form_for([#school_current, #quiz], :remote => true) do |f| %>
<div class="form-inputs" id="quiz_body">
<div class="form-group">
<label>Quiz Name (required)</label>
<%= f.text_field :name, class: "form-control", placeholder: "Enter quiz name here .." %>
</div>
<div class="form-group">
<label>Quiz Description (optional)</label>
<%= f.text_area :description, :rows => 10 , :cols => 10, class: "form-control", placeholder: "Enter quiz description here .." %>
</div>
</div>
<div id="question_list">
<ol>
<%= f.fields_for :questions do |builder| %>
<li class="question_field_item"><%= render "question_fields", f: builder %></li>
<% end %>
</ol>
</div>
<div class="form-actions">
<%= f.submit "save quiz", :data => {disable_with: "Saving ..."},class: "btn btn-primary text-uppercase", id: "save_quiz" %>
</div>
<% end %>
</div>
Make sure, single AJAX request is hitting the server
the following code block might be the culprit.
respond_to do |format|
if #quiz.save
format.html { render nothing: true }
else
format.html { render action: "new" }
end
end
Try extracting the saving from respond_to's block.
if #quiz.save
respond_to do |format|
format.html { render nothing: true }
end
else
respond_to do |format|
format.html { render action: "new" }
end
end
i figured out the problem. Call question.build twice in both new and create. That's why rails duplicates the record. Remove these lines of code. It will work.
questions.each do |index, question|
#quiz.questions.build(question)
end

Why is the check_box value not posting to the db

When I submit the form below the "published" check_box value is not posting.
params3 = {"utf8"=>"✓",
"authenticity_token"=>"i4SbblLJKIwba9yD30sDQCsir28/xdUxQZ90qYTNn0A=",
"story"=>{"name"=>"asdsaddsad", "post"=>"asdasdasdasd",
"user_id"=>"13", "image_id"=>"1", "published"=>"1"}, "commit"=>"Save
Story", "action"=>"create", "controller"=>"stories"}
def create
#story = Story.new(story_params)
respond_to do |format|
if #story.save
format.html { redirect_to #story, notice: 'Story was successfully created.' }
format.json { render action: 'show', status: :created, location: #story }
else
format.html { render action: 'new' }
format.json { render json: #story.errors, status: :unprocessable_entity }
end
end
end
<%= form_for #story do |f| %>
<%= f.text_field :name, placeholder: "Enter Title" %>
<%= f.text_area :post, placeholder: "Enter Story" %>
<br/>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.hidden_field :image_id, value: #image.id %>
<%= f.label "Publish this" %>
<%= f.check_box :published %>
<%= f.submit "Save Story" %>
<% end %>
The data that is being passed to the action is story as seen in the params3 hash. Also, the published check box is being posted. Check boxes by default will pass a 1 or 0 to denote true / false. Rails will update the value accordingly and accept 1 or 0 for the value of a checkbox:
params3 = {"utf8"=>"✓", "authenticity_token"=>"i4SbblLJKIwba9yD30sDQCsir28/xdUxQZ90qYTNn0A=", "**story**"=>{"name"=>"asdsaddsad", "post"=>"asdasdasdasd", "user_id"=>"13", "image_id"=>"1", "published"=>"1"}, "commit"=>"Save Story", "action"=>"create", "controller"=>"stories"}
Therefore your object creation will need to use those params. Since you are using Rails 4, you will need to use strong_parameters which seems that you are. You will need to verify that published is an allowed value in your params hash.
def story_params
params.require(:story).permit(...., :published, ...)
end

Resources