nested attribute in rails - ruby-on-rails

I am trying to build a small recipe website. But when I try to use nested attribute for saving my child(recipe_ingredients) table through parent(recipe) action. It only generating ids for me without any data in it. Could any one help?
Model for recipe:
class Recipe < ActiveRecord::Base
has_many :recipe_ingredients
accepts_nested_attributes_for :recipe_ingredients, allow_destroy: true
end
Model for recipe_ingredients:
class RecipeIngredient < ActiveRecord::Base
belongs_to :recipe, inverse_of: :recipe_ingredients
end
Controller for recipe:
def create
#recipe = Recipe.new(recipe_params)
#recipe.recipe_ingredients.build
***binding.pry***
if #recipe.save
render json: #recipe, status: :created, location: #recipe
else
render json: #recipe.errors, status: :unprocessable_entity
end
end
def recipe_params
params.require(:recipes)
.permit(:name, :category, instruction: [], recipe_ingredients_attributes: [:amount, :ingredient, :measure])
end
```
After I check with rails console, my recipe_params is like below
[7] pry(#<RecipesController>)> recipe_params
Unpermitted parameter: recipe_ingredients
=> {"name"=>"an example recipe", "category"=>"fry", "instructions"=>["do it", "ignore it"]}
I don't know how to solve that "Unpermitted parameter" problem. Please help~ Thank you~

Try to change params.require(:recipes) in your recipe_params method to params.require(:recipe)
Hope it helps.

Related

Why does the JSON patch data from relationships not get saved via Ruby on Rails?

I have an Ruby on Rails api where the data is handled in JSON. When I want to update an entity all the attributes are getting updated persistently but changed relationships arent' getting handled correctly, the entity stays the same as before.
JSON data before and after the PATCH:
{"data":{"id":"26","type":"candidate","attributes":
{"place":"Ort","zip_code":"PLZ","address":"Adresse",
"date_of_birth":"2019-01-01T00:00:00.000Z","title":"Frau",
"first_name":"Vorname","last_name":"Nachname",
"email_address":"email#example.ch",
"confirm_terms_and_conditions":true},"relationships":
{"occupational_fields":{"data":[]}}}}
PATCH input:
Started PATCH "/candidates/26" for 127.0.0.1 at 2019-01-22
19:40:53 +0100
Processing by CandidatesController#update as JSON
Parameters: {"data"=>{"id"=>"26", "attributes"=>{"place"=>"Ort",
"zip_code"=>"PLZ", "address"=>"Adresse", "title"=>"Frau",
"first_name"=>"Vorname", "last_name"=>"Nachname",
"email_address"=>"email#example.ch",
"confirm_terms_and_conditions"=>true, "date_of_birth"=>"2019-01-
01T00:00:00.000Z"}, "relationships"=>{"occupational_fields"=>
{"data"=>[{"type"=>"occupational-fields", "id"=>“4“}]}},
"type"=>"candidates"}, "id"=>"26", "candidate"=>{}}
This are my models, Candidates and OccupationalFields are related via a has_many belongs_to_many relationship through one CandidatesOccupationalField:
class Candidate < ApplicationRecord
has_many :candidates_occupational_fields, dependent: :destroy
has_many :occupational_fields, through:
:candidates_occupational_fields, dependent: :nullify
end
class CandidatesOccupationalField < ApplicationRecord
belongs_to :candidate
belongs_to :occupational_field
end
class OccupationalField < ApplicationRecord
has_many :candidates_occupational_fields, dependent: :destroy
has_many :candidates, through: :candidates_occupational_fields,
dependent: :nullify
end
This is the used controller:
class CandidatesController < ApplicationController
before_action :set_candidate, only: %i[show update destroy]
# GET /candidates
def index
#candidates = Candidate.all
render json: CandidateSerializer.new(#candidates).serialized_json
end
# GET /candidates/1
def show
#candidate = Candidate.find(params[:id])
render json: CandidateSerializer.new(#candidate).serialized_json
end
# POST /candidates
def create
#candidate = Candidate.new(candidate_params)
if #candidate.save
render json: CandidateSerializer.new(#candidate), status: :created
else
render json: #candidate.errors, status: :unprocessable_entity
end
end
# PATCH/PUT /candidates/1
def update
#candidate = Candidate.find(params[:id])
if #candidate.update(candidate_params)
render json: CandidateSerializer.new(#candidate)
else
render status: :unprocessable_entity
end
end
# DELETE /candidates/1
def destroy
#candidate.destroy
end
private
# Use callbacks to share common setup or constraints between actions.
def set_candidate
#candidate = Candidate.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def candidate_params
params.require(:data)[:attributes]
.permit(:place, :zip_code, :address,
:date_of_birth, :title, :first_name,
:last_name, :email_address,
:confirm_terms_and_conditions,
occupational_field_ids: [])
end
end
The JSON formatting is handled by fastjsonapi, this are the used serializers:
class CandidateSerializer
include FastJsonapi::ObjectSerializer
attributes :place, :zip_code, :address, :date_of_birth,
:title, :first_name, :last_name, :email_address,
:confirm_terms_and_conditions
has_many :occupational_fields
end
class OccupationalFieldSerializer
include FastJsonapi::ObjectSerializer
attributes :field
has_many :candidates
end
Thank you for your help.
The problem was, that the used serializer fast_jsonapi can't be used as deserializer and the Rail's strong parameters can't handle the json input. It works with the gem restful-jsonapi and modified params as shown in the example of the readme of restful-jsonapi.

Rails nested association is not saving

I’m trying to save a nested association, but for some reason it’s not working. Does anyone see anything wrong with this?
Order:
class Order < ApplicationRecord
has_many :replenishable_products, through: :order_items
has_many :order_items
accepts_nested_attributes_for :order_items
end
OrderItem
class OrderItem < ApplicationRecord
belongs_to :order
has_one :replenishable_product
accepts_nested_attributes_for :replenishable_product
end
ReplenishableProduct
class ReplenishableProduct < ActiveRecord::Base
belongs_to :order_item
end
Order Controller
def create
#order = #customer.orders.new(order_params)
authorize #order
if #order.save
render json: #order, serializer: ::V1::OrderSerializer, status: :created
else
render json: #order.errors, status: :unprocessable_entity
end
end
def order_params
params.require(:order).permit(order_items_attributes: [:quantity, :product_id, :selling_unit_of_measure_id,
replenishable_product_attributes: [:product_id, :salesperson_id,
:customer_id, :replenishable_date]])
end
Example request data:
```
{"order"=><ActionController::Parameters {"additional_tax_total"=>"8.27", "basket_id"=>"1", "custom_order_number"=>"pf000", "customer_attributes"=>{"contact_name"=>"Jason Test", "email"=>"new#test.com", "phone"=>"6095453234"}, "order_items_attributes"=>[{"product_id"=>"1", "quantity"=>"5", "replenishable_product_attributes"=>{"customer_id"=>"1", "product_id"=>"1", "replenishable_date"=>"2017-06-09T13:00:39-04:00", "salesperson_id"=>"1"}, "selling_unit_of_measure_id"=>"1"}, {"product_id"=>"2", "quantity"=>"5", "selling_unit_of_measure_id"=>"2"}], "payment_total"=>"103.31", "salesperson_id"=>"1", "shipping_address"=>"Test", "special_instructions"=>"test"} permitted: false>, "customer_id"=>"1", "format"=>"json", "controller"=>"api/v1/orders", "action"=>"create"}
```
So every other association is saving fine, but the replenishable_product is not being saved. I looked over it a few times and I don't see why it wouldn't be saving. Anyone have any ideas?

simple_fields_for with check_boxes error

Good night friends!
In a form with many through, I need to display all the objects of a given class (tool), with a checkbox field and text field next to it. My form is as follows:
= simple_form_for #service, html: { class: 'form-horizontal' } do |f|
- #tools.each do |tool|
= f.simple_fields_for :instrumentalisations, tool do |i|
= i.input :tool_id, tool.id, as: :check_boxes
= i.input :amount
But I'm getting the following error:
Undefined method `tool_id 'for # <Tool: 0x007faef0327c28>
Did you mean To_gid
Models
class Service < ApplicationRecord
has_many :partitions, class_name: "Partition", foreign_key: "service_id"
has_many :steps, :through => :partitions
has_many :instrumentalisations
has_many :tools, :through => :instrumentalisations
accepts_nested_attributes_for :instrumentalisations
end
class Tool < ApplicationRecord
has_many :instrumentalisations
has_many :services, :through => :instrumentalisations
accepts_nested_attributes_for :services
end
class Instrumentalisation < ApplicationRecord
belongs_to :service
belongs_to :tool
end
Controller
def new
#service = Service.new
#service.instrumentalisations.build
end
def edit
#tools = Tool.all
end
def create
#service = Service.new(service_params)
respond_to do |format|
if #service.save
format.html { redirect_to #service, notice: 'Service was successfully created.' }
format.json { render :show, status: :created, location: #service }
else
format.html { render :new }
format.json { render json: #service.errors, status: :unprocessable_entity }
end
end
end
def service_params
params.require(:service).permit(:name, :description, :price, :runtime, :status, step_ids: [], instrumentalisations_attributes: [ :id, :service_id, :tool_id, :amount ])
end
Thank you!
the error is quite simple: tool doesn't has a tool_id method. BUT, why are you asking this to a tool object instead of a instrumentalisation object?
So, you're trying to create some instrumentalisations but you're passing a tool as object:
f.simple_fields_for :instrumentalisations, **tool** do |i|
fields_for requires a record_name, whith in this case is :instrumentalisations and the 2nd arg is the record_object, which should be an instrumentalisations object and not a tool object.
So to fix it would have to pass an instrumentalisation object. You can accomplish that by:
f.simple_fields_for :instrumentalisations, Instrumentalisation.new(tool: tool) do |i|
Of course this isn't the best solution since if you edit this object would be building a lot of new instrumentalisations.
I'd recommend the cocoon gem, which makes it easier to handle nested forms!

Rails Paperclip Attachment not saving because polymorphic id not assigned

I am brand new here. I have been fighting with a rails app for hours now and need an answer. I have searched and tried many suggestions related to what I am trying to accomplish, but to no avail. I got the paperclip gem running for my rails app yesterday, and it was a breeze to add an attachment to a single model. However, I defined an agnostic, polymorphic attachments table to hold attached files for all models that need this functionality.
My issue is that I cannot get the attached file to save through nested parameters. All my parameters are accepted, but the db rolls back and doesn't save (using guard). Message is: 'attachments.attachable_id'=>'can't be blank'. I need this to be the foreign key of the related table, and this has to be saved along with the attachment_type. Here's what I have:
class ReportsController < ApplicationController
def new
#report = Report.new
#report.attachments.build(attachable_id: #report.id)
end
def create
#report = Report.new(params)
#report.attachments.build
respond_to do |format|
if #report.save
format.html { redirect_to #report, notice: 'Report was successfully created.' }
format.json { render json: #report, status: :created, location: #report }
else
format.html { render action: "new" }
format.json { render json: #report.errors, status: :unprocessable_entity }
end
end
end
private
def report_params
params.require(:report).permit(:filing_year, :filing_number, :order_number, :location, :environmental_review,:biological_review, :cultural_review, :date_received, :status, attachments_attributes: [:id, :attachable_id, :attachable_type, :attachment])
end
end
And for the models:
class Attachment < ActiveRecord::Base
belongs_to :attachable, polymorphic: true
validates :attachable_id, :attachable_type, presence: true
do_not_validate_attachment_file_type :attachment
Paperclip.interpolates :attached_to do |attachment, style|
attachment.instance.attachable.class.to_s.downcase
end
has_attached_file :attachment,
:url => "/attachments/:id/:basename.:extension",
:path => ":rails_root/public/attachments/:attached_to/:id/:basename.:extension",
:default_url => "/attachments/original/no-file.txt"
end
class Report < ActiveRecord::Base
has_one :environmental_review
has_many :attachments, as: :attachable
accepts_nested_attributes_for :attachments
validates :order_number, presence: true
.
.
.
end
And view (in slim):
.report
= form_for #report do |f|
.
.
.
= f.fields_for :attachments do |a|
= a.file_field :attachment
.
.
.
Thank you.
Well for one in your create method you call #reports.attachments.build again, but don't set the assignable_id, you need to do that. The other thing you can do is add a hidden form field that has the name attachable_id.

Has And Belongs to Many Through Save and Update

Here are my models:
class Examination < ActiveRecord::Base
has_many :categorizations
has_many :exam_statuses, :through => :categorizations
end
class Categorization < ActiveRecord::Base
belongs_to :examination
belongs_to :exam_status
end
class ExamStatus < ActiveRecord::Base
has_many :categorizations
has_many :examinations, :through => :categorizations
end
I can assign relations from the console without any problem by typing;
e = Examination.first
e.exam_status_ids = [1,2]
And also in the examinations/index.html.erb file I can list exam_statuses without any problem.
The problem is, I can't update or create any exam_status relations from examinations/_form.html.erb file!
I'm trying to make this with simple_form:
<%= f.association :exam_statuses, as: :check_boxes, label: 'Sınavın Durumu' %>
Its listing all the statuses with checkboxes but not updating them.
Logs saying:
"Unpermitted parameters: exam_status_ids"
And finally my controller, which is generated by "scaffold" by default, for update is:
def update
respond_to do |format|
if #examination.update(examination_params)
format.html { redirect_to #examination, notice: 'Examination was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #examination.errors, status: :unprocessable_entity }
end
end
end
From what your logs say, you should permit the parameter, in the controller:
def examination_params
params.require(:examination).permit(:exam_status_ids)
end
Don't forget to add other parameters in the permit call!
Then you can use it in your controller's action:
def update
...
#examination.update_attributes! examination_params
...
end
I think you need to use accepts_nested_attributes in this case to get it updated.
For more details you can refer this article

Resources