I can't figure out what I am doing wrong, but my nested form will not save to my room table.
Here's my view
new.html.erb
<h1>Room Assignments</h1>
<p>
<%= form_for #member do |f| %>
<%= f.label :name, "Member name" %><br>
<%= f.text_area :name %><br>`enter code here`
<%= f.fields_for :room do |b| %>
<%= b.label :room_name %><br>
<%= b.text_area :room_name %><br>
<%= b.label :rent %><br>
<%= b.text_area :rent %><br>
<% end %>
<%= f.submit "Submit" %>
<% end %>
members_controller.rb
class MembersController < ApplicationController
def new
#member = Member.new
#member.purchases.build
#room = #member.build_room
end
def index
#member = Member.all
end
def create
#member = Member.create(member_params)
#room = #member.create_room
if #member.save
redirect_to new_purchase_url
else
render :new
end
end
def show
#member = Member.find(params[:id])
end
def member_params
params.require(:member).permit(:name, :room_id,
room_attributes: [:rent, :name, :id, :member_id],
purchase_attributes: [:description, :cost, :id, :member_id])
end
end
member.rb
class Member < ActiveRecord::Base
belongs_to :room
has_many :purchases
accepts_nested_attributes_for :purchases, :room
end
room.rb
class Room < ActiveRecord::Base
has_one :member, foreign_key: "member_id"
has_many :purchases
end
This is what prints out in the rails console when I check to see if it has saved:
2.0.0-p451 :070 > Member.last
Member Load (0.3ms) SELECT "members".* FROM "members" ORDER BY "members"."id" DESC LIMIT 1
=> #<Member id: 24, name: "Tom", room_id: 38>
2.0.0-p451 :071 > Room.last
Room Load (0.3ms) SELECT "rooms".* FROM "rooms" ORDER BY "rooms"."id" DESC LIMIT 1
=> #<Room id: 38, room_name: nil, rent: nil, member_id: nil>
The problem is that you're calling #room = #member.create_room in the create action. The previous line should have already pulled in the parameters and built the member and room instances. So when you call create_room you're actually replacing the room that was added with a new (blank) one. Here's what I would do:
def create
#member = Member.new(member_params)
if #member.save
redirect_to new_purchase_url
else
render :new
end
end
Related
I've a multiple relation table named Order which belongs_to a Relai(to avoid singular/plurials complications), a Customer and a Composition. I set my Order model accordingly with nested_attributes as mentioned below. Before adding the customer part, I want to send a mail with just the #composition and a #relai chose with a dropdown.
class Order < ApplicationRecord
belongs_to :relai
belongs_to :composition
accepts_nested_attributes_for :relai
accepts_nested_attributes_for :composition
end
I set my OrdersController to get the :composition_id from my params
def new
#order = Order.new
#composition = Composition.find(params[:composition_id])
#relais = Relai.all
end
def create
#florist = Florist.first
#composition = Composition.find(params[:composition_id])
##relai = Relai.find(params[:relai_id]) # If I add this line it returns "Couldn't find Relai without an ID"
#order = Order.new(order_params)
if #order.save!
raise
OrderMailer.order_mail(#order).deliver
redirect_to thanks_purchase_path
else
render :new
end
end
private
def order_params
params.require(:order).permit(
florist_attributes: [:id],
relai_attributes: [:id, :name, :address],
composition_attributes: [:id, :name]
)
end
My View:
<%= form_with(model: #order, url: composition_orders_path(#composition), local: true) do |compo| %>
<%= compo.collection_select :relai, #relais, :id, :name %>
<%= compo.fields_for :composition do |fc| %>
<%= fc.collection_select :composition, #compositions, :id, :name %>
<% end %>
# Start Block that doesn't display the Relai.all
#<%#= compo.fields_for :relai do |fr| %>
#<%#= fr.label :relai, 'Ici la liste des relais :' %>
#<%#= fr.association :relai, collection: #relais %>
#<%#= fr.association :relai, #relais, :id, :name %>
#<%# end %>
# End Block
<%= compo.submit "MAIL", class: "app-form-button" %>
<% end %>
And the routes:
resources :compositions, only: [:show, :index] do
resources :orders, only: [:show, :new, :create, :index]
end
I also tried:
"nested_attributes" which seems to not works (I can't see my Relai collection in view.
=> https://www.pluralsight.com/guides/ruby-on-rails-nested-attributes)
the "optional: true" in model which throw me an error of:
PG::NotNullViolation: ERROR: null value in column "relai_id" of relation "orders" violates not-null constraint
Can someone explain me why I got a "Validation failed: Relai must exist, Composition must exist" whereas these appears in my params?
{"authenticity_token"=>"[FILTERED]", "order"=>{"relai"=>"2"}, "commit"=>"MAIL", "composition_id"=>"3"}
I'm on Rails 6.1.4 ; Ruby 2.6.6
accepts_nested_attributes_for works from parent to children. You are using it on the child side (Order).
If you just need to assign an existing Relai and Composition to Order just use a select for both of them:
class Order < ApplicationRecord
belongs_to :relai
belongs_to :composition
end
def new
#order = Order.new
#compositions = Composition.all
#relais = Relai.all
end
def create
#order = Order.new(order_params)
if #order.save!
OrderMailer.order_mail(#order).deliver
redirect_to thanks_purchase_path
else
render :new
end
end
private
def order_params
params.require(:order).permit(:relai_id, :composition_id)
end
<%= form_with(model: #order, url: composition_orders_path(#composition), local: true) do |compo| %>
<%= compo.collection_select :relai_id, #relais, :id, :name %>
<%= compo.collection_select :composition_id, #compositions, :id, :name %>
<%= compo.submit "MAIL", class: "app-form-button" %>
<% end %>
EDIT: Setting Composition on the controller.
def new
composition = Composition.find(params[:composition_id])
#order = Order.new(composition: composition)
#relais = Relai.all
end
def create
#order = Order.new(order_params)
if #order.save!
OrderMailer.order_mail(#order).deliver
redirect_to thanks_purchase_path
else
render :new
end
end
private
def order_params
params.require(:order).permit(:relai_id, :composition_id)
end
<%= form_with(model: #order, url: composition_orders_path(#composition), local: true) do |compo| %>
<%= compo.collection_select :relai_id, #relais, :id, :name %>
<%= compo.hidden_field :composition_id %>
<%= compo.submit "MAIL", class: "app-form-button" %>
<% end %>
In my application I have multiple user roles defined using an enum:
enum role: { staff: 0, clinician: 1, admin: 2 }
Staff users each belong to a university:
Staff Concern:
require 'active_support/concern'
module StaffUser
extend ActiveSupport::Concern
included do
belongs_to :university
has_many :patients
has_many :referral_requests
validates :university_id, presence: true, if: :staff?
end
University Model
class University < ApplicationRecord
has_many :staffs, -> { where role: :staff}, class_name: "User"
has_many :clinicians, through: :lists
has_many :whitelists
belongs_to :market
validates :market_id, presence: true
end
I have a dropdown select menu for Staff Doctor on a patients/new view where I want to display a list of staff users who belong to the same university as the current user, but I can't seem to get it to work. Currently, the dropdown only contains the prompt text. What am I doing wrong?
patients/new view:
<%= form_for(#patient) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="checkbox">
<h1>Tell us about your patient</h1>
<h2>Insurance</h2>
<% Insurance.all.each do |insurance| %>
<%= check_box_tag "patient[insurance_ids][]", insurance.id, #patient.insurance_ids.include?(insurance.id), id: dom_id(insurance) %>
<%= label_tag dom_id(insurance), insurance.name %><br>
<% end %>
<h2>Presenting Concerns</h2>
<% Concern.all.each do |concern| %>
<%= check_box_tag "patient[concern_ids][]", concern.id, #patient.concern_ids.include?(concern.id), id: dom_id(concern) %>
<%= label_tag dom_id(concern), concern.name %><br>
<% end %>
<h2>Staff Doctor</h2>
<%= select_tag "patient[staff_doctor_id]", options_from_collection_for_select(User.where("role = ? AND university_id = ?", "staff", #user.university_id), "id", "name"), prompt: "Select this patient's therapist" %>
</div>
<%= f.submit "Submit", class: "btn btn-primary" %>
<% end %
Patients Controller:
class PatientsController < ApplicationController
before_action :require_login
def new
#user = current_user
#patient = current_user.patients.build
end
def index
authorize Patient
#patients = policy_scope(Patient)
end
def show
#patient = Patient.find(params[:id])
end
def edit
#patient = Patient.find(params[:id])
end
def update
#patients = Patient.all
#patient = Patient.find(params[:id])
if #patient.update_attributes(patient_params)
flash[:success] = "Patient Updated!"
render 'patients/index'
else
render "edit"
end
end
def create
#patient = current_user.patients.build(patient_params)
if #patient.save
flash[:success] = "Patient Created!"
redirect_to new_referral_request_path(patient_id: #patient.id)
else
Rails.logger.info(#patient.errors.inspect)
render 'patients/new'
end
end
private
def patient_params
params.require(:patient).permit(:age, :staff_doctor_id, :user_id, insurance_ids: [], gender_ids: [], concern_ids: [], race_ids: [])
end
end
Scopes in ActiveRecord are chainable:
User.staff.where(university: #user.university)
Chaining .where or scopes creates AND clauses. So all the conditions must apply.
Using ActiveRecord::Enum creates scopes for each of the enum states. So this is equivilent to:
User.where(role: :staff, university: #user.university)
When using an ActiveRecord::Enum you need to remember that the database stores integers - not strings:
User.where('role = 0') # staff
User.where('role = ?', User.statuses[:staff])
But there is no need to use a SQL string for this query.
A much better way to create selects and checkboxes is by using the rails collection helpers:
<%= form_for(#patient) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="checkbox">
<h1>Tell us about your patient</h1>
<h2>Insurance</h2>
<%= f.collection_check_boxes(:insurance_ids, Insurance.all, :id, :name) %>
<h2>Presenting Concerns</h2>
<%= f.collection_check_boxes(:concern_ids, Concern.all, :id, :name) %>
<h2>Staff Doctor</h2>
<%= f.collection_select(:staff_doctor_id, User.staff.where(university: #user.university), :id, :name, prompt: "Select this patient's therapist") %>
</div>
<%= f.submit "Submit", class: "btn btn-primary" %>
<% end %>
Not only is this a lot less code, but binding the inputs to the form builder ensures that they "hold the value" when validations fail.
I am having a weird issue that I can't figure out.
It is very basic rails programming : I want to create an association between a user model and a goal model.
goal.rb
class Goal < ActiveRecord::Base
belongs_to :user
end
user.rb
class User < ActiveRecord::Base
has_many :goals, dependent: :destroy
has_many :records
has_many :orders
end
When I am making the association from the console, it is working well, lets say :
$ goal = Goal.first
$ goal.user_id = 1
$ goal.save
$ goal.inspect
#<Goal id: 1, description: "loremipsum", created_at: "2016-11-26 12:39:34", updated_at: "2016-11-26 12:43:41", name: "ipsumlorem", user_id: 1>
But then, when I am creating a goal from my views, the association is not made, and the user_id of the goal user_id remain : nil.
Any ideas ?
EDIT AS REQUIRED :
_form.html.erb
<%= form_for(#goal) do |f| %>
<%= f.text_field :name, class: "form-control" %>
<%= f.text_area :description, class: "form-control" %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
goal_controller.rb
def new
#users = User.all
#goal = current_user.goals.build
end
def edit
end
def create
#goal = Goal.new(goal_params)
#goal.save
redirect_to root_path, notice: "Objectif sauvegardé"
end
def create
# Here!!!!
#goal = current_user.goals.new(goal_params)
#goal.save
redirect_to root_path, notice: "Objectif sauvegardé"
end
Upon clicking submit only the Duel attributes are passing - not Dueler.
duels_controller.rb
def new
#duel = Duel.new
#user = User.find(params[:challenge_daddy]) # This pulls in the ID for Challenged User
# Current User
#duel.duelers << Dueler.new(user_id: current_user.id, user_name: current_user.name, user_last_name: current_user.last_name)
#current_user_challenges = current_user.challenges.order(:created_at)
# Challenged User
#duel.duelers << Dueler.new(user_id: #user.id, user_name: #user.name, user_last_name: #user.last_name)
#challenged_user_challenges = #user.challenges.order(:created_at)
respond_with(#duel)
end
I think I have to submerge the dueler info (i.e. full_name and collection_select) within something like <%= simple_form_for(#dueler) do |f| %>, but then I don't want two separate submit buttons. When the user clicks submit the dueler and duel information should both submit since they go hand-in-hand. Right now only the duel information submits and the duelers are never created.
duels/_form.html.erb
<%= simple_form_for(#duel) do |f| %>
<%= current_user.full_name %> WILL <%= collection_select(:dueler, :challenge_id, #current_user_challenges, :id, :full_challenge, include_blank: true) %>
<%= #user.full_name %> WILL <%= collection_select(:dueler, :challenge_id, #challenged_user_challenges, :id, :full_challenge, include_blank: true) %>
THE LOSER WILL <%= f.text_field :consequence %>.
<%= f.submit %>
<% end %>
UPDATE
Originally I had this in the _form:
<%= f.fields_for :duelers do |dueler| %>
<%= render 'dueler_fields', :f => dueler %>
<% end %>
But I took it out because the duels_controller new logic wasn't passing into it so I moved the code directly into the _form, but now I'm not sure what should take the place of <%= f.fields_for :duelers do |dueler| %>
class Dueler < ActiveRecord::Base
belongs_to :user
belongs_to :challenge
belongs_to :duel
end
class Duel < ActiveRecord::Base
belongs_to :user
belongs_to :challenge
has_many :duelers
accepts_nested_attributes_for :duelers, :reject_if => :all_blank, :allow_destroy => true #correct
end
class DuelsController < ApplicationController
before_action :set_duel, only: [:show, :edit, :update, :destroy, :duel_request]
respond_to :html
def index
#duels = Duel.joins(:duelers).all
redirect_to duel(#duel)
end
def duel_request
#dueler = #duel.duelers.where(user_id: current_user)
end
def show
#dueler = Dueler.find_by(user_id: current_user.id)
respond_with(#duel)
end
def user_challenges
#user = User.find_by_name(params[:name])
#challenges = #user.challenges.order(:created_at)
end
def new
#duel = Duel.new
#user = User.find(params[:challenge_daddy])
#duel.duelers << Dueler.new(user_id: current_user.id, user_name: current_user.name, user_last_name: current_user.last_name)
#current_user_challenges = current_user.challenges.order(:created_at)
#duel.duelers << Dueler.new(user_id: #user.id, user_name: #user.name, user_last_name: #user.last_name)
#challenged_user_challenges = #user.challenges.order(:created_at)
respond_with(#duel)
end
def edit
end
def create
#duel = Duel.new(duel_params)
#duel.save
#redirect_to duel_request_url(#duel)
respond_with(#duel)
end
def update
#duel.update(duel_params[:duelers_attributes])
respond_with(#duel)
end
def destroy
#duel.destroy
respond_with(#duel)
end
private
def set_duel
#duel = Duel.find(params[:id])
end
def duel_params
params.require(:duel).permit(:consequence, :reward, duelers_attributes: [:id, :user_id, :challenge_id, :accept])
end
end
If you are using has_many and belongs_to with accepts_nested_attributes you will need to use inverse_of to prevent Rails from attempting to lookup records (which of course don't exist because you haven't yet created them)
Change your Duel model has_many declaration to:
has_many :duelers, inverse_of: :duel
For further details on this and an example of a nested form with has_many relationship using Simple Forms check out:
https://robots.thoughtbot.com/accepts-nested-attributes-for-with-has-many-through
Hello I have 2 models Products and ProductImage. Product has_many ProductImages. I am using paperclip gem.
When i submit the Product Form i get this error.
No handler found for ["0", {"product_image"=>#<ActionDispatch::Http::UploadedFile:0x007f8cb78b29c8 #tempfile=#<Tempfile:/var/folders/yx/znmx6qfj0c507bvkym6lvhxh0000gn/T/RackMultipart20151221-46388-dqxfk7.jpg>, #original_filename="780069_black_l.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"product[product_images_attributes][0][product_image]\"; filename=\"780069_black_l.jpg\"\r\nContent-Type: image/jpeg\r\n">}]
def create_product_images
params["product"]["product_images_attributes"].each do |image|
ProductImage.create(product_image: image, product_id: #form.product.id)
end
end
Anyone know how to fix this? Im trying to create a ProductImage. So when i go product.product_images i have an array of all the images for the product.
Here is the form
<%= javascript_include_tag "custom" %>
<div class="container">
<div class=“row”>
<div class="col-md-6 col-md-offset-3">
<div class="panel panel-primary">
<div class="panel-body">
<%= simple_form_for #product do |f| %>
<%= f.fields_for :product_images do |product_image| %>
<% if product_image.object.new_record? %>
<%= product_image.file_field(:product_image) %>
<% else %>
<%= image_tag(product_image.url(:thumb)) %>
<%= product_image.hidden_field :_destroy %>
<%= product_image.link_to_remove "X" %>
<% end %>
<% end %>
<%= f.collection_select :category_id, #categories, :id, :name, include_blank: true, prompt: "Select One Category" %>
<% #categories.each do |category| %>
<div class='sizes_container' id ='sizes_container_for_<%= category.id %>'>
<% category.sizes.each do |size| %>
<%= label_tag "product_form[sizes_by_id][#{size.id}]", size.title %>
<%= text_field_tag "product_form[sizes_by_id][#{size.id}]" %>
<% end %>
</div>
<% end %>
<%= f.input :title, label:"Title"%>
<%= f.input :price, label:"Price"%>
<%= f.input :description,label:"Description" %>
<%= f.input :size_description, label:"Size Details"%>
<%= f.input :shipping_description, label:"Shipping Details"%>
<%= f.input :tag_list,label:"Tags - Seperate tags using comma ','. 5 tags allowed per product" %>
<%= f.button :submit, "Create new product", class: "btn-lg btn-success" %>
<% end %>
</div>
</div>
</div>
</div>
</div>
This is what the params look like
69: def create_product_images
70: params["product"]["product_images_attributes"].each do |image|
=> 71: binding.pry
72: ProductImage.create(product_image: image, product_id: #form.product.id)
73: end
74: end
[1] pry(#<ProductsController>)> params["product"]["product_images_attributes"]
=> {"0"=>
{"product_image"=>
#<ActionDispatch::Http::UploadedFile:0x007f8cacd89b28
#content_type="image/jpeg",
#headers="Content-Disposition: form-data; name=\"product[product_images_attributes][0][product_image]\"; filename=\"780069_black_l.jpg\"\r\nContent-Type: image/jpeg\r\n",
#original_filename="780069_black_l.jpg",
#tempfile=#<File:/var/folders/yx/znmx6qfj0c507bvkym6lvhxh0000gn/T/RackMultipart20151221-46388-d4pub9.jpg>>},
"1"=>
{"product_image"=>
#<ActionDispatch::Http::UploadedFile:0x007f8cacd897b8
#content_type="image/jpeg",
#headers="Content-Disposition: form-data; name=\"product[product_images_attributes][1][product_image]\"; filename=\"20090a.jpg\"\r\nContent-Type: image/jpeg\r\n",
#original_filename="20090a.
Product Controller
class ProductsController < ApplicationController
before_action :set_product, only: [:edit, :show, :update]
before_action :correct_user_edit, only: [:edit, :update, :destroy]
before_action :logged_in_user, only: [:new, :edit, :update, :destroy]
def index
#products = Product.all
end
def new
#product = Product.new
#categories = Category.preload(:sizes).order(:name)
#product.product_images.build
end
def home
#products = Product.paginate(page: params[:page])
end
def edit
end
def show
end
def update
if #product.update(product_params)
redirect_to #product
flash[:success] = 'Item was successfully updated.'
else
render "edit"
end
end
def create
#form = ProductForm.new(
product_image: product_params[:product_image],
title: product_params[:title],
price: product_params[:price],
size_description: product_params[:size_description],
shipping_description: product_params[:shipping_description],
description: product_params[:description],
tag_list: product_params[:tag_list],
category_id: product_params[:category_id],
sizes_by_id: product_params[:sizes_by_id],
user: current_user
)
if #form.save
create_product_images
redirect_to #form.product
flash[:success] = "You have created a new product"
else
flash[:danger] = "Your product didn't save"
new
render "new"
end
end
def destroy
#product.destroy
flash[:success] = "Product deleted"
redirect_to user_products_path
end
private
def create_product_images
params["product"]["product_images_attributes"].each do |index, image|
ProductImage.create(product_image: image, product_id: #form.product.id)
end
end
def set_product
#product = Product.find(params[:id])
end
def product_params
params.require(:product).permit(
:product_images_attributes,
:title,
:price,
:description,
:tag_list,
:category_id,
:size_description,
:shipping_description,
).merge(sizes_by_id: params[:product_form][:sizes_by_id]) # TODO
end
def correct_user_edit
if #product = current_user.products.find_by(id: params[:id])
else
redirect_to root_url if #product.nil?
end
end
end
product_form.rb
class ProductForm
attr_reader :quantity_by_size_id, :product
def initialize(product_image:, title:, price:, description:, tag_list:, category_id:, sizes_by_id:, user:, size_description:, shipping_description:)
#quantity_by_size_id = sizes_by_id # TODO
#product_images = product_image
#product = Product.new(
title: title,
price: price,
description: description,
tag_list: tag_list,
category_id: category_id,
size_description: size_description,
shipping_description: shipping_description,
user: user
)
build_product_sizes
end
def save
product.save
end
private
def build_product_sizes
quantity_by_size_id.map do |size_id, quantity|
if quantity.to_i.nonzero?
product.product_sizes.build(product: product, size_id: size_id, quantity: quantity)
end
end
end
end
Product.rb
class Product < ActiveRecord::Base
acts_as_taggable
belongs_to :user
belongs_to :category
has_many :product_sizes
has_many :product_images, :dependent => :destroy
validates :title, presence: true, length: { maximum: 30 }
validates :description, presence: true, length: { maximum: 2000 }
validates :category, :user, :price, presence: true
accepts_nested_attributes_for :product_images, allow_destroy: true
end
schema
create_table "product_sizes", force: :cascade do |t|
t.integer "quantity"
t.integer "product_id"
t.integer "size_id"
end
product_size.rb
class ProductSize < ActiveRecord::Base
belongs_to :product
belongs_to :size
validates :quantity, presence: true
end
params
From: /Users/jo/Documents/Safsy/Website/Safsy/Safsy/app/controllers/products_controller.rb # line 36 ProductsController#create:
35: def create
=> 36: binding.pry
37: #form = ProductForm.new(
38: product_image: product_params[:product_image],
39: title: product_params[:title],
40: price: product_params[:price],
41: size_description: product_params[:size_description],
42: shipping_description: product_params[:shipping_description],
43: description: product_params[:description],
44: tag_list: product_params[:tag_list],
45: category_id: product_params[:category_id],
46: sizes_by_id: product_params[:sizes_by_id],
47: user: current_user
48: )
49: if #form.save
50: create_product_images
51: redirect_to #form.product
52: flash[:success] = "You have created a new product"
53: else
54: flash[:danger] = "Your product didn't save"
55: new
56: render "new"
57: end
58: end
[1] pry(#<ProductsController>)> params
=> {"utf8"=>"✓",
"authenticity_token"=>"3MZESoSUgrO2Bc3vl8/M0pTfTna9rjeXfXG23znsy3VGCEBcHMh+4ZC5rqSxGkQOmz4kl1JN9FFMH4lniDjFQg==",
"product"=>
{"product_images_attributes"=>
{"0"=>
{"product_image"=>
#<ActionDispatch::Http::UploadedFile:0x007f8c9ceb22f8
#content_type="image/jpeg",
#headers="Content-Disposition: form-data; name=\"product[product_images_attributes][0][product_image]\"; filename=\"780069_black_l.jpg\"\r\nContent-Type: image/jpeg\r\n",
#original_filename="780069_black_l.jpg",
#tempfile=#<File:/var/folders/yx/znmx6qfj0c507bvkym6lvhxh0000gn/T/RackMultipart20151222-46388-pgfg4b.jpg>>,
"_destroy"=>"false"},
"1450783221367"=>
{"product_image"=>
#<ActionDispatch::Http::UploadedFile:0x007f8c9ceb2140
#content_type="image/jpeg",
#headers="Content-Disposition: form-data; name=\"product[product_images_attributes][1450783221367][product_image]\"; filename=\"20090a.jpg\"\r\nContent-Type: image/jpeg\r\n",
#original_filename="20090a.jpg",
#tempfile=#<File:/var/folders/yx/znmx6qfj0c507bvkym6lvhxh0000gn/T/RackMultipart20151222-46388-3vamt4.jpg>>,
"_destroy"=>"false"}},
"category_id"=>"3",
"title"=>"new product",
"price"=>"352.40",
"description"=>"test",
"size_description"=>"test",
"shipping_description"=>"test",
"tag_list"=>"test"},
"product_form"=>{"sizes_by_id"=>{"1"=>"3", "2"=>"34", "3"=>""}},
"commit"=>"Create new product",
"controller"=>"products",
"action"=>"create"}
[2] pry(#<ProductsController>)> product_params
Unpermitted parameter: product_images_attributes
=> {"title"=>"new product",
"price"=>"352.40",
"description"=>"test",
"tag_list"=>"test",
"category_id"=>"3",
"size_description"=>"test",
"shipping_description"=>"test",
"sizes_by_id"=>{"1"=>"3", "2"=>"34", "3"=>""}}
[3] pry(#<ProductsController>)>
Update
After trying Rich Peck's answer i have the product images persisting and product.product_images is now working
My product_params look like this.
def product_params
params.require(:product).permit(
:title,
:price,
:description,
:tag_list,
:category_id,
:size_description,
:shipping_description,
product_images_attributes: [:product_image, :_destroy],
product_sizes_attributes: [:size_id, :quantity]
)
end
Why are you looping through your params and performing a create method?
--
You should just be able to pass the images through to your nested model with accepts_nested_attributes_for:
#app/models/product.rb
class Product < ActiveRecord::Base
has_many :product_images
accepts_nested_attributes_for :product_images, allow_destroy: true
end
#app/models/product_image.rb
class ProductImage < ActiveRecord::Base
belongs_to :product
has_attached_file :product_image
end
This should pass the nested image object from your #product form to your ProductImage model.
As long as you permit the right parameters, it should work fine for you:
#app/controllers/products_controller.rb
class ProductsController < ApplicationController
def new
#product = Product.new
#product.product_images.build
end
def create
#product = Product.new product_params
#product.save
end
private
def product_params
params.require(:product).permit(:product, :params, product_images_attributes: [:product_image] %>
end
end
Your form looks okay.
Update
Okay, in regards to saving ProductSize along with the image, you can use accetps_nested_attributes_for to save them at the same time...
I would always advocate using this instead of trying to create your own classes in an after_create call or whatever -- keeping the flow consistent is the most important thing you can do.
Anyway...
#app/models/product.rb
class Product < ActiveRecord::Base
has_many :product_images
has_many :product_sizes
accepts_nested_attributes_for :product_images, :product_sizes
end
#app/models/product_size.rb
class ProductSize < ActiveRecord::Base
belongs_to :product
end
#app/models/product_image.rb
class ProductImage < ActiveRecord::Base
belongs_to :product
has_attached_image :image
end
This will allow you to use the following controller setup:
#app/controllers/products_controller.rb
class ProductsController < ApplicationController
def new
#product = Product.new
#product.product_images.build
#product.product_sizes.build
end
def create
#product = Product.new product_params
#product.save
end
private
def product_params
params.require(:product).permit(:x, :y, :z, product_images_attributes: [:image], product_sizes_attributes: [:a, :b, :c])
end
end
This will allow you to use a similar setup to what you have currently:
#app/views/products/new.html.erb
<%= form_for #product do |f| %>
<%= f.fields_for :product_images do |p| %>
<%= p.file_field :image %>
<% end %>
<%= f.fields_for :product_sizes do |s| %>
<%= s.text_field :a %>
<% end %>
<%= f.submit %>
<% end %>
This will allow you to use all the validations you require etc, and if you use Cocoon, you'll be able to add extra sizes as you require.
You don't have an Array, it seems a Hash there.
Your Hash looks like {"ID" => IMAGE}
Try to iterate over an id and image like this:
params["product"]["product_images_attributes"].each do |index, image|