Validation failed: Stocks product must exist, Stocks location must exist - ruby-on-rails

I have three models -> locations, products and stocks.
Stocks is a join table of locations and products.
When creating a new product i used fields_for to show locations and even though i got it to work, for some reason now it does not seem to work anymore and it gives me the above error.
<div class="input-field">
<%= f.label :product_name %>
<%= f.text_field :name, autofocus: true %>
</div>
<div class="input-field">
<%= f.label :price %>
<%= f.text_field :price, autofocus: true %>
</div>
<% if !#edit %>
<%= f.fields_for :stocks do |ff| %>
<div class="input-field margin-top x-4">
<%= ff.collection_select :location_id, Location.all, :id, :structured_location , {:prompt => "Please Select Locations for Product"}, {multiple: true} %>
<%= ff.label :locations %>
</div>
<div class="input-field">
<%= ff.label :quantity %>
<%= ff.text_field :quantity %>
</div>
<div class="input-field">
<%= ff.label :threshold_quantity %>
<%= ff.text_field :threshold_quantity %>
</div>
<% end %>
<% else %>
<%= collection_select :product, :location_ids, Location.all, :id, :structured_location , {:prompt => "Please Select Locations for Product"}, {multiple: true} %>
<% end %>
<div class="row margin-top x-4">
<div class="col s12 center-align">
<%= f.submit "#{current_page?(new_product_path) ? "Create Product" : "Update Product"}", class: "btn wave-effect pink darken-1 btn-large" %>
</div>
</div>
controller
class ProductsController < ApplicationController
helper_method :sort_column, :sort_direction
def index
#products = Product.order(sort_column + " " + sort_direction)
end
def new
#product = Product.new
#product.stocks.build
end
def create
#product = Product.new(product_params)
if #product.save!
flash[:notice] = "Successfully saved..."
redirect_to products_path
else
flash[:alert] = "Something went wrong, please check the values you entered"
redirect_to :back
end
end
private
def product_params
params.require(:product).permit(:name,:price, location_ids: [], stocks_attributes: [:id, :quantity, :threshold_quantity, location_id: []])
end
end
product model
class Product < ApplicationRecord
has_many :stocks, dependent: :destroy
has_many :locations, :through => :stocks
accepts_nested_attributes_for :stocks
end
parameters in rails console
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"l1BFhrdyB2QMO5k3+60GNiPphFfF+DXDGPbUU3V2Op2aekObjgIe13k8uoedmDIEZgIeXPZUeS/0VxQXkKa1Uw==",
"product"=>{"name"=>"Soap", "price"=>"10", "location_ids"=>["", "1",
"2"], "stocks_attributes"=>{"0"=>{"quantity"=>"100",
"threshold_quantity"=>"100"}}}, "commit"=>"Create Product"}

After hours of searching i stumbled upon this post
BigBinary
it seems that Rails 5 made belongs_to relationship IDs required by default thats why i had validations failed and i couldn't find anything about it.
simply adding optional: true in my stock model worked!
class Stock < ApplicationRecord
belongs_to :location, optional: true
belongs_to :product, optional: true
accepts_nested_attributes_for :product, allow_destroy: true
accepts_nested_attributes_for :location, allow_destroy: true
end

Related

How to edit and update attributes in join table in has_many: through association?

I have has_many through join table for Product-Warehouse setup where product and warehouse connect through warehouse_products. warehouse_product includes product_id ,warehouse_id ,item_count and low_threshold.
Question: Going to a product edit page allows to change the item_counts and thresholds of that product at all warehouses.
The edit.htlm.erb looks like :
<%= f.label 'Product Name' %><br>
<%= f.text_field :product_name %><br>
<%= f.label 'Sku_Code' %><br>
<%= f.text_field :sku_code%><br>
<%= fields_for :warehouse_products do |i|%>
<%= i.number_field :item_count %><br>
<%= i.number_field :low_threshold%><br>
<% end %>
<%= submit_tag "Edit Product" %>
The edit and update functions:
def edit
#products = Product.find(params[:id])
end
def update
#products = Product.find(params[:id])
if #products.update_attributes!(product_params)
redirect_to action: "index", notice: 'Product was successfully updated.'
else
redirect_to action: "edit"
end
end
private
def product_params
params.require(:product).permit(warehouse_products_attributes: [:item_count ,:low_threshold])
end
How do I update the item_count and low_threshold for all the warehouses(Mumbai,Delhi etc).
I am not 100% sure what causes your issue, but you might try this:
In your warehouse model:
has_many :warehouse_products, dependent: :destroy
has_many :products, through: :warehouse_products
accepts_nested_attributes_for :warehouse_products, reject_if: :all_blank, allow_destroy: true
In your warehouse_product model:
belongs_to :warehouse
belongs_to :product
In your product model:
has_many :warehouse_products, dependent: :destroy
has_many :warehouses, through: :warehouse_products
accepts_nested_attributes_for :warehouse_products, reject_if: :all_blank, allow_destroy: true
And in your controller's permitted attributes:
warehouse_products_attributes: [:id, :warehouse_id, :item_count, :low_threshold, :_destroy],
Update
Your form:
<%= form_for :product do |f| %>
<%= f.label 'Product Name' %>
<br>
<%= f.text_field :product_name %>
<br>
<%= f.label 'Sku_Code' %>
<br>
<%= f.text_field :sku_code%>
<br>
<%= fields_for :warehouse_products do |i| %>
<% Warehouse.all.each do |warehouse| %>
<div class="warehouse_fields">
<label for="warehouse-<%= warehouse.id %>">
<%= i.radio_button :warehouse_id, warehouse.id, id: "warehouse-#{warehouse.id}", class: "warehouse" %>
<span>
<%= warehouse.name %>
</span>
</label>
</div>
<% end %>
<br>
<%= i.label :item_count, 'Item Count' %>
<br>
<%= i.number_field :item_count %>
<br>
<%= i.label 'Low Threshold' %>
<br>
<%= i.number_field :low_threshold %>
<% end %>
<% end %>
Your controller:
def product_params
params.require(:product).permit(
:sku_code,
:product_name,
warehouse_products_attributes: [:id, :warehouse_id, :item_count, :low_threshold, :_destroy]
)
end

Rails not saving /permitting value of nested forms to be stored

My _feature.html.erb looks like-
<%= error_messages_for(#project) %>
<div class="card m-auto shadow-lg p-3 mb-5 bg-white rounded">
<div class="card-body">
<%= form_for [#project, #feature], class: "form-group inline", remote: true do |builder| %>
<%= builder.hidden_field :feature_token_id, value: auto_generate_id %>
<%= builder.hidden_field :category, class: "form-control", value: category_value %>
<%= builder.label :name %>
<%= builder.text_field :name, required: true, class: "form-control" %>
<%= builder.label :desc, "Description" %>
<%= builder.text_field :desc, class: "form-control" %>
<%= builder.fields_for :task, remote: true do |form| %>
<div class="form-group">
<%= form.label :name %>
<%= form.text_field :name, required:true, class: "form-control" %>
</div>
<div class="form-check">
<%= form.check_box :completed, class: "form-check-input" %>
<%= form.label :completed %>
</div>
<div class="form-group">
<%= form.label :user_id, "Select the User to Assign this task:" %><br>
<%= form.collection_select :user_id, User.all, :id, :name %>
</div>
<% end %>
<%= builder.submit class: "btn btn-primary m-2" %>
<% end %>
</div>
</div>
And my FeaturesContrller is ->
class FeaturesController < ApplicationController
before_action :set_project
def index
#features=Feature.all
end
def new
#feature=Feature.new
#feature.tasks.new
end
def create
#feature=#project.features.new(feature_params)
binding.pry
if #feature.save
redirect_to #project
else
render "new"
end
end
private
def set_project
#project=Project.find(params[:project_id])
end
def feature_params
params.require(:feature).permit(:name, :desc, :category, :feature_token_id, tasks_attributes: [:name])
end
end
But while I try to save the form values only the Feature table gets updated but the tasks_attributes remain unpermitted instead of permitting them, what is the wrong thing I am doing?
And here is the log from pry
13: def create
14: #feature=#project.features.new(feature_params)
=> 15: binding.pry
16: if #feature.save
17: redirect_to #project
18: else
19: render "new"
20: end
21: end
[1] pry(#<FeaturesController>)> feature_params
Unpermitted parameter: :task
=> <ActionController::Parameters {"name"=>"ayann", "desc"=>"uhi", "category"=>"Current Iteration", "feature_token_id"=>"38378"} permitted: true>
[2] pry(#<FeaturesController>)>
And If I exit from pry only Feature table is updated with new value not Task table!(Log looks like)
Feature Create (0.8ms) INSERT INTO `features` (`name`, `desc`, `feature_token_id`, `project_id`, `created_at`, `updated_at`, `category`) VALUES ('ayann', 'uhi', '38378', 4, '2019-08-20 07:55:27', '2019-08-20 07:55:27', 'Current Iteration')
My feature.rb model ->
class Feature < ApplicationRecord
belongs_to :project
has_many :tasks, dependent: :destroy
accepts_nested_attributes_for :tasks
end
And task.rb model ->
class Task < ApplicationRecord
belongs_to :feature
belongs_to :user, optional: true
end
what is the reason that my nested model task is not being saved?
The problem is in the _feature.html.erb file, in building the form for accepting nested attributes for tasks. The line <%= builder.fields_for :task, remote: true do |form| %> tries to build a form for the relation task, but the Feature model has a has_many relation with tasks. Changing that line to builder.fields_for :tasks will pass the parameters as expected (as tasks_attributes and not task_attributes, which is probably being sent currently).

How do I save a form in double nested form?

I have three models: Event, Workout, and Round.
A person can create a event, that includes a workout, and configure number of sets and weights through round.
I am currently using cocoon gem to create a nested form. I am able to use the form and save Event and Workout, however, Round is not being saved.
class Event < ActiveRecord::Base
has_many :workouts, dependent: :destroy
has_many :rounds, :through => :workouts
belongs_to :user
accepts_nested_attributes_for :workouts, :allow_destroy => true
end
class Workout < ActiveRecord::Base
belongs_to :event
has_many :rounds, dependent: :destroy
accepts_nested_attributes_for :rounds, :allow_destroy => true
end
class Round < ActiveRecord::Base
belongs_to :workout
belongs_to :event
end
I currently have my routes set like this.
Rails.application.routes.draw do
devise_for :users
root 'static_pages#index'
resources :events do
resources :workouts do
resources :rounds
end
end
In my controller, this is how I have my new methods.
New Method for Event
def new
#event = current_user.events.new
end
New Method for Workout
def new
#workout = Workout.new
end
New Method for Round
def new
#round = Round.new
end
I currently have the form under Events' view folder. Under show.html.erb of Events view file, I am trying to display Rounds as well by
<% #workout.rounds.each do |round| %>
<%= round.weight %>
<% end %>
But I am getting undefined method for rounds. Is it not possible to display round in Event view?
Thanks for the help!
Edit 1:
Here is my nested forms.
At the top, I have form for Event.
<%= simple_form_for #event do |f| %>
<%= f.input :title %>
<h3>Work Outs</h3>
<div id="workouts">
<%= f.simple_fields_for :workouts do |workout| %>
<%= render 'workout_fields', f: workout %>
<% end %>
<div class="links">
<%= link_to_add_association 'add workout', f, :workouts %>
</div>
</div>
<div class="field">
<%= f.label :start_time %><br>
<%= f.datetime_select :start_time %>
</div>
<div class="field">
<%= f.label :end_time %><br>
<%= f.datetime_select :end_time %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="actions">
<%= f.submit "Create new Workout" %>
</div>
<% end %>
<% end %>
</form>
Then there is a form for Workout
<div class="nested-fields">
<%= f.input :name %>
<div class="rounds">
<%= f.simple_fields_for :rounds, :wrapper => 'inline' do |round| %>
<%= render 'round_fields', f: round %>
<% end %>
<div class="links">
<%= link_to_add_association 'add round', f, :rounds, :render_option => { :wrapper => 'inline' } %>
</div>
</div>
<%= link_to_remove_association "remove workout", f %>
</div>
And finally, I have the form for Round
<div class="nested-fields">
<table class="table round-table">
<tr>
<td>
<% index = 0 %>
<%= f.simple_fields_for :rounds do |round| %>
<%= render 'set_fields', {f: round, index: index} %>
<% index = index + 1 %>
<% end %>
</td>
<td>Previous Weight</td>
<td><%= f.input_field :weight %></td>
<td><%= f.input_field :repetition %></td>
<td><%= link_to_remove_association "remove rounds", f %></td>
</tr>
</table>
</div>
I am able to create round on rails console and save them. But when I use the form on the web, I cannot save them.
EDIT 2
This is currently how I have the event_params and workout_params set-up.
def event_params
params.fetch(:event, {}).permit(:title, :description, :start_time, :end_time, :workouts_attributes => [:id, :name, :category, :_destroy])
end
Then the workout_params:
def workout_params
params.require(:workout).permit(:name, :category, :rounds_attributes => [:id, :weight, :set, :repetition, :_destroy])
end
I am confused why the form would save Event and Workout. But Round always returns an empty array.
Finally solved it!
I had to have an association in the params as well. Double nested association.
def event_params
params.fetch(:event, {}).permit(:title, :description, :start_time, :end_time, :workouts_attributes => [:id, :name, :category, :_destroy])
end
For my event_params, I only had :workouts_attributes. I thought having :rounds_attributes in workout_params would be okay. But I needed to have rounds_attributes in event_params as well.
Fixing it like below fixed the issue.
def event_params
params.fetch(:event, {}).permit(:title, :description, :start_time, :end_time, :workouts_attributes => [:id, :name, :category, :_destroy, :rounds_attributes => [:id, :weight, :set, :repetition, :_destroy]])
end
you already have rounds attribute in Events model (has_many :rounds, :through => :workouts), why not use it?
<% #event.rounds.each do |round|
<%= round.weight %>
<% end %>

has_many :through and collection_select rails form

I have tried all of the solutions to similar problems and haven't gotten this one figured out.
I have a has_many :through relationship between 'Clinician', and 'Patient' with a joined model 'CareGroupAssignment'. None of the methods I have tried so far been able to save the clinician to patient association. I would like to have a patient be able to have multiple clinicians associated with it and clinicians will have multiple patients.
clinician.rb (simplified)
class Clinician < ActiveRecord::Base
belongs_to :care_group
has_many :patients ,:through=> :care_group_assignments
has_many :care_group_assignments, :dependent => :destroy
belongs_to :user
accepts_nested_attributes_for :user, :allow_destroy => true
end
patient.rb
class Patient < ActiveRecord::Base
belongs_to :care_group
has_many :clinicians ,:through=> :care_group_assignments
has_many :care_group_assignments
belongs_to :user
accepts_nested_attributes_for :user, :allow_destroy => true
end
care_group_assignments.rb
class CareGroupAssignment < ActiveRecord::Base
belongs_to :clinician
belongs_to :patient
end
I first tried to follow the example from Railscasts PRO #17- HABTM Checkboxes to at least start getting the data collected and to have the models set up correctly. Below is the form with the checkboxes for each clinician as described in the RailsCast, checkboxes show up and the data is sent but not stored (can't figure out why).
patient new.html.erb form
<%= form_for #patient do |form| %>
<%= form.fields_for :user do |builder| %>
<div class="form-group">
<%= builder.label "Email or Username" %>
<%= builder.text_field :email, class: "form-control" %>
</div>
<div class="form-group">
<%= builder.label :password %>
<%= builder.password_field :password, class: "form-control" %>
</div>
<% end %>
<div class="form-group">
<%= form.label :first_name %>
<%= form.text_field :first_name, class: "form-control", placeholder: "First name" %>
</div>
<div class="form-group">
<%= form.label :last_name %>
<%= form.text_field :last_name, class: "form-control", placeholder: "Last name" %>
</div>
<div class="form-group">
<% Clinician.where(care_group_id: #care_group.id).each do |clinician| %>
<%= check_box_tag "patient[clinician_ids][]", clinician.id, #patient.clinician_ids.include?(clinician.id), id: dom_id(clinician) %>
<%= label_tag dom_id(clinician), clinician.full_name %><br>
<% end %>
</div>
<%= form.button 'Create Patient', class: "btn btn-u btn-success" %>
<% end %>
Next, I tried the collection_select answer to this question. This creates a badly formatted list where only one clinician can be selected. The data seems to get sent but again doesn't save.
patient new.html.erb form
<div class="form-group">
<%= collection_select(:patient, :clinician_ids,
Clinician.where(care_group_id: #care_group.id).order("first_name asc"),
:id, :full_name, {:selected => #patient.clinician_ids, :include_blank => true}, {:multiple => true}) %>
</div>
Lastly, I copied what was done in this questions/solution. Also isn't formatted as a normal collection_select dropdown but instead a list with a boarder around it where only one clinician can be selected.
patient new.html.erb form
<div class="form-group">
<% Clinician.where(care_group_id: #care_group.id).each do |clinician| %>
<%= check_box_tag "patient[clinician_ids][]", clinician.id, #patient.clinician_ids.include?(clinician.id), id: dom_id(clinician) %>
<%= label_tag dom_id(clinician), clinician.full_name %><br>
<% end %>
</div>
None of these methods have so far been able to save the clinician to patient association.
patient_controller.rb
def new
#patient = Patient.new
#user = User.new
#patient.build_user
#care_group = current_clinician.care_group
end
def create
#patient = Patient.create(patient_params)
#patient.care_group = current_clinician.care_group
if #patient.save
redirect_to patient_path(#patient), notice: "New patient created!"
else
render "new"
end
end
def show
#patient = Patient.find_by(id: params["id"])
end
private
def patient_params
params.require(:patient).permit({:clinician_ids => [:id]},:first_name,:last_name,:user_id,:care_group_id, user_attributes: [ :email, :password, :patient_id, :clinician_id ])
end
I plan to display the clinicians associated with a patient on the patient show page:
patient show.html.erb
<strong>Shared with:</strong>
<% #patient.clinicians.each do |clinician| %>
<%= clinician.full_name %><
<% end %>
This works if I seed the database but since the data doesn't seem to be stored, nothing is showing up.
Rails 4.1.8, ruby 2.2.1p85, PostgreSQL
Thanks
Found the answer on another question I asked:
problem is this line in the controller:
params.require(:patient).permit({:clinician_ids => [:id]}...
It should be:
params.require(:patient).permit({:clinician_ids => []}...

has_many :throught not INSTERING INTO database from form

I have tried all of the solutions to similar problems and haven't gotten this one figured out.
I have a has_many :through relationship between 'Clinician', and 'Patient' with a joined model 'CareGroupAssignment'. I would like to have a patient be able to have multiple clinicians associated with it and clinicians will have multiple patients.
When I submit my form this is logged:
Started POST "/patients" for 127.0.0.1 at 2015-09-02 14:56:38 -0700
Processing by PatientsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"XXX=", "patient"=>{"user_attributes"=>{"email"=>"allencentre", "password"=>"[FILTERED]"}, "first_name"=>"Allen", "last_name"=>"Centre", "birth_date(1i)"=>"2002", "birth_date(2i)"=>"9", "birth_date(3i)"=>"2", "clinician_ids"=>["85", "87"], "patient_deceased"=>"0", "patient_archived"=>"0"}, "button"=>""}
So "clinician_ids"=>["85", "87"] is being passed from the form.
There is an INSERT INTO "users" ("email", .... and an INSERT INTO "patients" ("bir.... but the data for care_group_assignments doesn't have one.
There is [36mCareGroupAssignment Load (0.4ms)[0m [1mSELECT "care_group_assignments".* FROM "care_group_assignments" WHERE "care_group_assignments"."patient_id" = $1[0m [["patient_id", 199]]
clinician.rb (simplified)
class Clinician < ActiveRecord::Base
belongs_to :care_group
has_many :patients ,:through=> :care_group_assignments
has_many :care_group_assignments, :dependent => :destroy
belongs_to :user
accepts_nested_attributes_for :user, :allow_destroy => true
end
patient.rb
class Patient < ActiveRecord::Base
belongs_to :care_group
has_many :clinicians ,:through=> :care_group_assignments
has_many :care_group_assignments
belongs_to :user
accepts_nested_attributes_for :user, :allow_destroy => true
end
care_group_assignments.rb
class CareGroupAssignment < ActiveRecord::Base
belongs_to :clinician
belongs_to :patient
end
This is following the example from Railscasts PRO #17- HABTM Checkboxes to at least start getting the data collected and to have the models set up correctly. Below is the form with the checkboxes for each clinician as described in the RailsCast, checkboxes show up and the data is sent but not stored (can't figure out why).
patient new.html.erb form
<%= form_for #patient do |form| %>
<%= form.fields_for :user do |builder| %>
<div class="form-group">
<%= builder.label "Email or Username" %>
<%= builder.text_field :email, class: "form-control" %>
</div>
<div class="form-group">
<%= builder.label :password %>
<%= builder.password_field :password, class: "form-control" %>
</div>
<% end %>
<div class="form-group">
<%= form.label :first_name %>
<%= form.text_field :first_name, class: "form-control", placeholder: "First name" %>
</div>
<div class="form-group">
<%= form.label :last_name %>
<%= form.text_field :last_name, class: "form-control", placeholder: "Last name" %>
</div>
<div class="form-group">
<% Clinician.where(care_group_id: #care_group.id).each do |clinician| %>
<%= check_box_tag "patient[clinician_ids][]", clinician.id, #patient.clinician_ids.include?(clinician.id), id: dom_id(clinician) %>
<%= label_tag dom_id(clinician), clinician.full_name %><br>
<% end %>
</div>
<%= form.button 'Create Patient', class: "btn btn-u btn-success" %>
<% end %>
This method has so far not been able to save the clinician to patient association.
patient_controller.rb
def new
#patient = Patient.new
#user = User.new
#patient.build_user
#care_group = current_clinician.care_group
end
def create
#patient = Patient.create(patient_params)
#patient.care_group = current_clinician.care_group
if #patient.save
redirect_to patient_path(#patient), notice: "New patient created!"
else
render "new"
end
end
def show
#patient = Patient.find_by(id: params["id"])
end
private
def patient_params
params.require(:patient).permit({:clinician_ids => [:id]},:first_name,:last_name,:user_id,:birth_date, user_attributes: [ :email, :password, :patient_id, :clinician_id ])
end
I plan to display the clinicians associated with a patient on the patient show page:
patient show.html.erb
<strong>Shared with:</strong>
<% #patient.clinicians.each do |clinician| %>
<%= clinician.full_name %><
<% end %>
This works if I seed the database but since the data doesn't seem to be stored, nothing is showing up.
Rails 4.1.8, ruby 2.2.1p85, PostgreSQL
Thanks
I believe your problem is this line in your controller:
params.require(:patient).permit({:clinician_ids => [:id]}...
It should be:
params.require(:patient).permit({:clinician_ids => []}...

Resources