Adding nested attribute to an existing Object - ruby-on-rails

I am using the gem cocoon for nested attributes
I have a Product model that has many sizes.
Creating Product and its sizes works well
I can update the :size_name and/or the :quantity attributes if a size exist. And I can destroy a size. Good...
But I CANNOT add more size to and existing product.
Is there a solution to add size in an existing product?
In product model I have:
has_many :sizes, inverse_of: :product, dependent: :destroy
accepts_nested_attributes_for :sizes, reject_if: :all_blank, allow_destroy: true
in my products_controller.rb
def update
if #product.update_attributes(params_product)
respond_to do |format|
format.html {redirect_to admin_product_path(#product)}
format.js
end
else
render :edit
end
end
def params_product
params.require(:product).permit(
:id,
:title,
:ref,
:brand,
:description,
:buying_price,
:price,
:category_id,
:color,
{ attachments:[]},
sizes_attributes: [:id, :size_name, :quantity, :_destroy]
)
end
the edit form
<%= f.simple_fields_for :sizes do |size| %>
<%= render "size_fields", f: size %>
<% end %>
<div class="links">
<%= link_to_add_association "Ajouter une taille", f, :sizes, partial: "size_fields", class: "btn btn-secondary btn-lg" %>
</div>
the partial
<div class="nested-fields">
<div class="row">
<div class="col-12 col-md-4">
<%= f.input :size_name, label: false, placeholder: "Taille", autofocus: true %>
</div>
<div class="col-12 col-md-4">
<%= f.input :quantity, label: false, placeholder: "Quantité dans cette taille" %>
</div>
<div class="col-12 col-md-4">
<%= link_to_remove_association "supprimer cette taille", f, class: "btn btn-danger delete_size" %>
<hr>
</div>
</div>
</div>
If you need more code feel free to ask :)
UPDATE
Feature test accept update on existing size, but Capybara don't find the new fields to add a new size... (WIP)
Here are the logs when I am adding a new sier to an existing product
Started PATCH "/admin/products/26" for 127.0.0.1 at 2019-02-16 11:31:51 +0100
[1m[36mUser Load (0.4ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2[0m [["id", 23], ["LIMIT", 1]]
↳ /Users/johan/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.2.2/lib/active_record/log_subscriber.rb:98
Processing by Admin::ProductsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"xG3tRqzIC0XP4quanEo2589zbsSiJcwICXjIt9ecndDsKjwYIDSBVZ4P62woGNgnCYHhBiM2jXmZlQjz9CK2fQ==", "product"=>{"category_id"=>"8", "brand"=>"Side Park", "title"=>"Jean", "color"=>"Bleu", "price"=>"30.0", "buying_price"=>"5.0", "ref"=>"SP02", "description"=>"Paalablalntalon blab", "sizes_attributes"=>{"0"=>{"size_name"=>"L", "quantity"=>"3", "_destroy"=>"false", "id"=>"97"}, "1"=>{"size_name"=>"S", "quantity"=>"3", "_destroy"=>"false", "id"=>"95"}, "2"=>{"size_name"=>"M", "quantity"=>"4", "_destroy"=>"false", "id"=>"96"}}}, "commit"=>"Mettre à jour l'article", "id"=>"26"}
[1m[36mProduct Load (0.3ms)[0m [1m[34mSELECT "products".* FROM "products" WHERE "products"."id" = $1 LIMIT $2[0m [["id", 26], ["LIMIT", 1]]
↳ app/controllers/admin/products_controller.rb:62
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
↳ app/controllers/admin/products_controller.rb:49
[1m[36mSize Load (0.5ms)[0m [1m[34mSELECT "sizes".* FROM "sizes" WHERE "sizes"."product_id" = $1 AND "sizes"."id" IN ($2, $3, $4)[0m [["product_id", 26], ["id", 97], ["id", 95], ["id", 96]]
↳ app/controllers/admin/products_controller.rb:49
[1m[35m (0.2ms)[0m [1m[35mCOMMIT[0m
↳ app/controllers/admin/products_controller.rb:49
Redirected to http://localhost:3000/admin/products/26
Completed 302 Found in 13ms (ActiveRecord: 1.0ms)

I added this to my product controller, I can now add sizes to an existing Product
def new
#product = Product.new
#product.sizes.build
end
def edit
#product.sizes.build
end

Related

Double nested form not sending attributes to controller

All help/hints/debugging tips/thoughts are welcome, as I'm pretty much stuck for some time on this issue.
I have a 2-level deep nested form. The parameters of the 1st level are saving correctly (e.g. options_attributes), but unfortunately the parameters of the deepest form are not being sent to the controller (.e.g. option_prices_attributes is not shown at all in my parameters. I use the cocoon gem to create a dynamic nester form.
Interestingly,
(1) in my console I am able to create a 2-level deep object where also the option_price parameters are saving.
(2) when using :option_prices_attributes in the simple_field forms, they are being sent as parameters:
{"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"P6oCZkZF8O+, "accommodation_category"=>{"options_attributes"=>{"1568305809712"=>{"name"=>"Option name", "_destroy"=>"false", "option_prices_attributes"=>{"name"=>"Option price", "_destroy"=>"0"}}}}, "commit"=>"Save", "park_id"=>"8", "id"=>"96"}
=> and consequently resulting in an error message in the terminal saying
no implicit conversion of Symbol into Integer
My models
class AccommodationCategory < ApplicationRecord
belongs_to :park
has_many :options, dependent: :destroy
accepts_nested_attributes_for :options, allow_destroy: true
end
class Option < ApplicationRecord
belongs_to :accommodation_category
has_many :option_prices, dependent: :destroy
accepts_nested_attributes_for :option_prices, allow_destroy: true
end
class OptionPrice < ApplicationRecord
belongs_to :option
end
Accommodation_categories_controller.rb
class AccommodationCategoriesController < ApplicationController
# skip_before_action :authenticate_user!
[...]
def update
#park = Park.find(params[:park_id])
#accommodation_category = #park.accommodation_categories.find(params[:id])
authorize #accommodation_category
#accommodation_category = #accommodation_category.update_attributes(accommodation_category_params)
end
def new_options
#accommodation_category = AccommodationCategory.find(params[:id])
#park = #accommodation_category.park
authorize #accommodation_category
#2nd level nesting
# #accommodation_category.options.build
#accommodation_category.options.each do |option|
option.option_prices.build
end
end
private
def accommodation_category_params
params.require(:accommodation_category).permit(:name, :description, :status, :persons_max, :persons_min, :persons_included, :accommodation_count, :enabled_accommodation_count, :thumb, :included_services, :photo,
options_attributes: [:name, :description, :_destroy,
option_prices_attributes: [:name, :price_type, :start_date, :end_date, :price, :duration, :duration_min, :duration_max, :backend_only, :weekend_extra, :_destroy]])
end
end
views/accommodation_categories/new_options.html.erb
<%= render 'options_new_form', park: #park%>
views/accommodation_categories/options_new_form.html.erb (1st level)
<%= simple_form_for [#park, #accommodation_category] do |f|%>
<h1> <%= #accommodation_category.name %> </h1>
<% #accommodation_category.options.each do |option| %>
<%= option %>
<% end %>
<%= f.simple_fields_for :options do |option| %>
<%= render 'option_fields', f: option %>
<% end %>
<div>
<%= link_to_add_association 'add option', f, :options %>
</div>
<%= f.submit "Save", class: "btn btn-primary" %>
<% end %>
views/accommodation_categories/option_fields.html.erb (2nd level)
<%= f.input :name %>
<%= f.check_box :_destroy %>
<%= link_to_remove_association "remove option", f %>
<%= f.simple_fields_for :option_prices do |option_price| %>
<%= render 'option_price_fields', f: option_price %>
<% end %>
<%= link_to_add_association 'add option price', f, :option_prices %>
views/accommodation_categories/option_price_fields.html.erb
<%= f.input :name %>
<%= f.check_box :_destroy %>
<%= link_to_remove_association "remove option price", f %>
The message in my terminal when sending the parameter to the controller is the following:
Processing by AccommodationCategoriesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"QlROXu9ImP6GSvPJQgd7eVZtaWsiVT6myWzZEFIEtEulSrQmt75XVMEI/avKUzhjZaZG9Kj0Pmih6J/4UYO8IQ==", "accommodation_category"=>{"options_attributes"=>{"1568290804865"=>{"name"=>"option name", "_destroy"=>"false"}}}, "commit"=>"Save", "park_id"=>"8", "id"=>"93"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
↳ /Users/xx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/activerecord-5.2.3/lib/active_record/log_subscriber.rb:98
Park Load (0.4ms) SELECT "parks".* FROM "parks" WHERE "parks"."id" = $1 LIMIT $2 [["id", 8], ["LIMIT", 1]]
↳ app/controllers/accommodation_categories_controller.rb:29
AccommodationCategory Load (0.2ms) SELECT "accommodation_categories".* FROM "accommodation_categories" WHERE "accommodation_categories"."park_id" = $1 AND "accommodation_categories"."id" = $2 LIMIT $3 [["park_id", 8], ["id", 93], ["LIMIT", 1]]
↳ app/controllers/accommodation_categories_controller.rb:30
(0.2ms) BEGIN
↳ app/controllers/accommodation_categories_controller.rb:32
Option Create (0.3ms) INSERT INTO "options" ("accommodation_category_id", "name", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["accommodation_category_id", 93], ["name", "option name"], ["created_at", "2019-09-12 12:20:14.265335"], ["updated_at", "2019-09-12 12:20:14.265335"]]
↳ app/controllers/accommodation_categories_controller.rb:32
(0.7ms) COMMIT
↳ app/controllers/accommodation_categories_controller.rb:32
AccommodationCategory Load (0.2ms) SELECT "accommodation_categories".* FROM "accommodation_categories" WHERE "accommodation_categories"."park_id" = $1 AND "accommodation_categories"."id" = $2 LIMIT $3 [["park_id", 8], ["id", 93], ["LIMIT", 1]]
↳ app/controllers/accommodation_categories_controller.rb:45
Redirected to http://localhost:3000/accommodation_categories/93/new_discounts
Completed 302 Found in 14ms (ActiveRecord: 2.3ms)
None of your nested-fields partials seem to have a wrapper-class? Cocoon explicitly relies on a specific mark-up, this could cause e.g. the nested fields to appear to be inserted correctly, but inserted outside of the form and then of course never posted to the server/controller.

Strong params not saved in nested form

In my app I want to create events that have nameand price
In these events I want to be able to add participants they have a first_nameand a salary
I am using the gem Cocoon for the nested forms
From the EventsController I am trying to create my participants...
I don't manage to get the right way to do this...
EventsController
class EventsController < ApplicationController
def new
#event = Event.new
#participant = Participant.new
end
def create
#event = Event.create(params_event)
if #event.save
#event.participants.create([{first_name: params[:first_name], salary: params[:salary], event_id: params[:id]}])
#binding.pry
redirect_to #event
end
end
def show
#event = Event.find(params[:id])
end
private
def params_event
params
.require(:event).permit(:name,:total_price,
participants_attributes: [:first_name, :salary, :_destroy ] )
end
end
I want that my create methode render an array of participants in the given event like this...
#event.participants.create!([john={first_name: "John", salary: 2000, event_id: params[:id]}, mike={first_name: "Mike", salary: 1400, event_id: params[:id]}])
Here is the result of binding.pry
8: def create
9: #event = Event.create(params_event)
10: if #event.save
11: #event.participants.create([{first_name: params[:first_name], salary: params[:salary], event_id: params[:id]}])
12: ##event.participants.create!([john={first_name: "John", salary: 2000, event_id: params[:id]}, mike={first_name: "Mike", salary: 1400, event_id: params[:id]}])
13: binding.pry
=> 14: redirect_to #event
15: end
16: end
[1] pry(#<EventsController>)>
[1] pry(#<EventsController>)> #event
=> #<Event:0x007f89f8013c98
id: 67,
name: "Rent a plane",
total_price: 3400,
created_at: Mon, 13 Mar 2017 01:18:24 UTC +00:00,
updated_at: Mon, 13 Mar 2017 01:18:24 UTC +00:00>
[2] pry(#<EventsController>)> #event.participants
Participant Load (0.2ms) SELECT "participants".* FROM "participants" WHERE "participants"."event_id" = $1 [["event_id", 67]]
=> [#<Participant:0x007f89f6773580
id: 30,
first_name: nil,
salary: nil,
created_at: Mon, 13 Mar 2017 01:18:24 UTC +00:00,
updated_at: Mon, 13 Mar 2017 01:18:24 UTC +00:00,
event_id: 67>]
If neeeded here are my models:
class Event < ApplicationRecord
has_many :participants, dependent: :destroy
accepts_nested_attributes_for :participants, reject_if: :all_blank, allow_destroy: true
end
class Participant < ApplicationRecord
belongs_to :event
end
And my forms:
new.html.erb
<%= simple_form_for #event do |f| %>
<%= f.input :name, label: "Event's name" %>
<%= f.input :total_price, label: "What is the total price" %>
<h2> Add your friends to share the bill</h2>
<%= f.simple_fields_for :participants do |participant| %>
<%= render "events/participants_fields", f: participant %>
<% end %>
<%= link_to_add_association 'add a friend', f, :participants, partial: "events/participants_fields", class:"btn btn-primary" %>
<%= f.button :submit %>
<% end %>
partial: _participants_fields.html.erb
<div class='nested-fields participant-background'>
<%= f.input :first_name, label: "Enter your friend's first name" %>
<%= f.input :salary, label: "Enter his/her monthly pay" %>
<%= link_to_remove_association "Remove this friend", f , class: "btn btn-danger btn-xs" %>
</div>
EDIT
These are my logs when I create an event with participants they aren't saved: ( I just kept the #event = Event.new(params_event)
tarted GET "/" for ::1 at 2017-03-13 13:55:20 +0100
ActiveRecord::SchemaMigration Load (7.0ms) SELECT "schema_migrations".* FROM "schema_migrations"
Processing by EventsController#new as HTML
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Rendering events/new.html.erb within layouts/application
Rendered events/_participants_fields.html.erb (5.8ms)
Rendered events/new.html.erb within layouts/application (98.6ms)
Rendered shared/_navbar.html.erb (2.5ms)
Rendered shared/_flashes.html.erb (0.4ms)
Completed 200 OK in 408ms (Views: 358.0ms | ActiveRecord: 20.9ms)
Started POST "/events" for ::1 at 2017-03-13 13:55:48 +0100
Processing by EventsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"mMuWIZe06ofG6DCafY2EPrJouIcF4YzKKJx6Y9ct5XUZNHqIyvFY4l3dqiEnxC5NhQapvSnFDukgblJnHg+14g==", "event"=>{"name"=>"Rent a van", "total_price"=>"390"}, "commit"=>"Create Event"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
(0.1ms) BEGIN
SQL (11.9ms) INSERT INTO "events" ("name", "total_price", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["name", "Rent a van"], ["total_price", 390], ["created_at", 2017-03-13 12:55:48 UTC], ["updated_at", 2017-03-13 12:55:48 UTC]]
(6.0ms) COMMIT
(0.2ms) BEGIN
(0.2ms) COMMIT
Redirected to http://localhost:3000/events/93
Completed 302 Found in 25ms (ActiveRecord: 18.6ms)
Started GET "/events/93" for ::1 at 2017-03-13 13:55:48 +0100
Processing by EventsController#show as HTML
Parameters: {"id"=>"93"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Event Load (0.4ms) SELECT "events".* FROM "events" WHERE "events"."id" = $1 LIMIT $2 [["id", 93], ["LIMIT", 1]]
Rendering events/show.html.erb within layouts/application
Participant Load (0.5ms) SELECT "participants".* FROM "participants" WHERE "participants"."event_id" = $1 [["event_id", 93]]
Rendered events/show.html.erb within layouts/application (3.1ms)
Rendered shared/_navbar.html.erb (3.3ms)
Rendered shared/_flashes.html.erb (0.8ms)
Completed 200 OK in 41ms (Views: 34.1ms | ActiveRecord: 1.5ms)
The problem was in my forms....
Cocoon needs special div
<div class="container">
<div class="col-xs-12">
<%= simple_form_for #event do |f| %>
<%= f.input :name, label: "Event's name" %>
<%= f.input :total_price, label: "What is the total price" %>
<h2> Add your friends to share the bill</h2>
<div id="participants">
<%= f.simple_fields_for :participants do |participant| %>
<%= render "events/participants_fields", f: participant %>
<% end %>
</div>
<div class="links">
<%= link_to_add_association 'add a friend', f, :participants, partial: "events/participants_fields", class:"btn btn-primary" %>
</div>
<%= f.button :submit %>
<% end %>
</div>
</div>
I cleaned the controller like so:
class EventsController < ApplicationController
def new
#event = Event.new
end
def create
#event = Event.new(params_event)
if #event.save
redirect_to event_path(#event)
end
end
def show
#event = Event.find(params[:id])
end
private
def params_event
params
.require(:event).permit(:name,:total_price, participants_attributes: [:first_name, :salary, :_destroy ] )
end
end

Why does my Registrations#Update devise action not update all attributes in my `User` model?

This is my views/devise/registrations/edit.html.erb:
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put, class: "edit-user-form m-t" }) do |f| %>
<%= f.error_notification %>
<div class="form-group">
<%= f.input_field :email, required: true, autofocus: true %>
</div>
<div class="form-group">
<%= f.input_field :current_password, hint: "we need your current password to confirm your changes", placeholder: "current password", required: true %>
</div>
<div class="form-group">
<%= f.input_field :password, autocomplete: "off", hint: "leave it blank if you don't want to change it", placeholder: "new password", required: false %>
</div>
<div class="form-group">
<%= f.input_field :password_confirmation, placeholder: "confirm new password", required: false %>
</div>
<div class="form-group">
<%= f.association :school, collection: School.where(school_type: [:college, :university]), prompt: "Choose a school", class: 'col-lg-4 form-control', label: false %>
</div>
</div>
<div class="form-group">
<div class="col-lg-12 text-center">
<%= f.button :submit, "Update", class: "btn btn-lg edit-account-update-button" %>
</div>
</div>
<% end %>
And this is my ApplicationController:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
check_authorization :unless => :devise_controller?
rescue_from CanCan::AccessDenied do |exception|
respond_to do |format|
format.json { head :forbidden }
format.html { redirect_back(fallback_location: root_path, flash: { danger: exception.message }) }
end
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:account_update, keys: [:avatar, :avatar_cache, :remove_avatar, :school_id])
end
end
The issue though is that it isn't updating the record, here is the log from that operation:
Started PUT "/users" for ::1 at 2016-11-02 19:22:59 -0500
Processing by DeviseInvitable::RegistrationsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Xo445XVpElgDmfcjywZKEbsXIqZR/2Wgw==", "user"=>{"remove_avatar"=>"0", "avatar_cache"=>"", "email"=>"coach#test.com", "current_password"=>"[FILTERED]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "school_id"=>"3"}, "commit"=>"Update"}
User Load (4.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 7], ["LIMIT", 1]]
User Load (9.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 7], ["LIMIT", 1]]
(0.7ms) BEGIN
SQL (4.2ms) UPDATE "users" SET "updated_at" = $1, "avatar" = $2 WHERE "users"."id" = $3 [["updated_at", 2016-11-03 00:22:59 UTC], ["avatar", "a1.jpg"], ["id", 7]]
(0.8ms) COMMIT
Redirected to http://localhost:3000/
Completed 302 Found in 139ms (ActiveRecord: 19.1ms)
Note that the school_id is set in the params, so we know it properly accepts the input from the form. But the SQL UPDATE statement, doesn't include school_id, so it doesn't actually save that info to the DB.
Also note that there are no unpermitted params messages in the log.
What could be causing this?
Edit 1
This is the School.rb model:
class School < ApplicationRecord
has_many :users
enum school_type: { high_school: 0, college: 1, university: 2 }
end
This is the User.rb model:
class User < ActiveRecord::Base
belongs_to :school
end
The problem was that your devise model User was inheriting ActiveRecord::Base instead of ApplicationRecord which is an abstract class in Rails 5. With the inheritance of latter, most of the gems which deal with models can and do modify the code of ActiveRecord::Base in their own context without affecting other models, which isn't possible if you inherit the former.
Source: Why Rails 5 uses ApplicationRecord instead of ActiveRecord::Base?

Rails 4. Attribute not saving when creating model

I am stumped as to why this isn't working. I have a review system, and a link to create a new review passing 2 attributes; user_id and gigid. Both id's are being generated as integers but when I save the review, the gigid saves as 'nil' rather than the integer.
View:
<%= link_to 'Click here to rate this user', new_user_review_path(:user_id => request.user.id, :gigid => request.gig.id) %>
Here both ID's are set correctly (according to server output). User_id is the user which is to be reviewed (works correctly) and gigid is a reference for post validation. (works correctly until I try and save)
_form :
<%= simple_form_for([#user, #user.reviews.build]) do |f| %>
<div id="rating-form">
<label>Rating</label>
</div>
<%= f.input :comment %>
<%= f.button :submit %>
<% end %>
Controller:
def new
if user_signed_in?
#review = current_user.reviews.new
else
redirect_to(root_url)
flash[:danger] = "You must log in to rate a user"
end
end
def create
#review = #user.reviews.new review_params
#review.reviewed_id = current_user.id
if #review.save
redirect_to user_path(#user)
else
render 'new'
end
end
private
def review_params
params.require(:review).permit(:rating, :comment, :gigid, :user_id)
end
end
Server output when clicking link:
Started GET "/users/21/reviews/new?gigid=17&locale=en" for 127.0.0.1 at 2016-01-13 18:08:26 +0100
Processing by ReviewsController#new as HTML
Parameters: {"gigid"=>"17", "locale"=>"en", "user_id"=>"21"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 21]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
Rendered reviews/_form.html.erb (4.9ms)
I then add a comment and a rating and click create.
Server output when clicking create:
Started POST "/users/21/reviews?locale=en" for 127.0.0.1 at 2016-01-13 18:10:44 +0100
Processing by ReviewsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"RToZwvodvXxQp1/spEhgemO/oi+4rof8jREuLw27CcEsEBqFWGLeYne1CgH3kvWu9OzAV+bHvOk9g9nq8JMPnw==", "review"=>{"rating"=>"5", "comment"=>"sdfsdfdd"}, "commit"=>"Create Review", "locale"=>"en", "user_id"=>"21"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 21]]
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
(0.1ms) begin transaction
SQL (0.7ms) INSERT INTO "reviews" ("rating", "comment", "user_id", "reviewed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?) [["rating", 5], ["comment", "sdfsdfdd"], ["user_id", 21], ["reviewed_id", 1], ["created_at", "2016-01-13 17:10:44.675386"], ["updated_at", "2016-01-13 17:10:44.675386"]]
(93.6ms) commit transaction
I notice that 'gigid' is being completely ignored here, but EVERYTHING else saves fine.
I don't understand why one attribute saves and the other doesn't, any insight would be greatly appreciated!
Your form doesn't have anything for gigid to send it to create action. You can use hidden field in the form like below
<%= simple_form_for([#user, #user.reviews.build]) do |f| %>
<div id="rating-form">
<label>Rating</label>
</div>
<%= f.input :comment %>
<%= f.input :gigid, :as => :hidden, :input_html => { :value => params[:gigid] }
<%= f.button :submit %>
<% end %>
There is no gigid in review params. Look carefully on your params when you are performing POST: "review"=>{"rating"=>"5", "comment"=>"sdfsdfdd"}. Just review and comment. And after it you are doing:
params.require(:review).permit(:rating, :comment, :gigid, :user_id)

Rails4: To check for no image uploaded with carrierwave is not working when delete the image

What I want to do is for users to select at least one image (up to 3 images) and to enter f.text_area :content in \views\shared\ _article_form.html.erb.
I added a custom validation check_for_at_least_image in \models\article.rb.
It works (error message is displayed) only in create action, but it doesn't work in update action.
How can I check no image and display error message in update action.
article has many photo.
The logs are as followings.
\log/development.log
no image when new create (error message was displayed as I expect)
Started POST "/articles" for 127.0.0.1 at 2014-09-13 10:40:49 +0900
Processing by ArticlesController#create as HTML
Parameters: {"utf8"=>"笨・, "authenticity_token"=>"xxxx=", "article"=>{"category_id"=>"1379", "photos_attributes"=>{"0"=>{"article_id"=>""}, "1"=>{"article_id"=>""}, "2"=>{"article_id"=>""}}, "content"=>"test"}, "commit"=>"逋サ骭イ縺吶k"}
[1m[35mUser Load (0.0ms)[0m SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'xxxx' LIMIT 1
[1m[36m (0.0ms)[0m [1mbegin transaction[0m
[1m[35m (0.0ms)[0m rollback transaction
[1m[36mCategory Load (1.0ms)[0m [1mSELECT "categories".* FROM "categories" WHERE "categories"."id" = ? LIMIT 1[0m [["id", 1379]]
Rendered shared/_error_messages.html.erb (1.0ms)
Rendered shared/_article_form.html.erb (8.0ms)
Rendered articles/new.html.erb within layouts/application (10.0ms)
Rendered layouts/_header.html.erb (1.0ms)
Rendered layouts/_footer.html.erb (0.0ms)
Completed 200 OK in 63ms (Views: 51.0ms | ActiveRecord: 1.0ms)
delete all(three) images (no error message was displayed)
Started PATCH "/articles/40" for 127.0.0.1 at 2014-09-13 11:10:00 +0900
Processing by ArticlesController#update as HTML
Parameters: {"utf8"=>"笨・, "authenticity_token"=>"xxxx=", "article"=>{"category_id"=>"1379", "photos_attributes"=>{"0"=>{"article_id"=>"40", "_destroy"=>"1", "id"=>"132"}, "1"=>{"article_id"=>"40", "_destroy"=>"1", "id"=>"133"}, "2"=>{"article_id"=>"40", "_destroy"=>"1", "id"=>"134"}}, "content"=>"test"}, "commit"=>"譖エ譁ー縺吶k", "id"=>"40"}
[1m[35mUser Load (0.0ms)[0m SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'xxxx' LIMIT 1
[1m[36mArticle Load (0.0ms)[0m [1mSELECT "articles".* FROM "articles" WHERE "articles"."user_id" = ? AND "articles"."id" = 40 ORDER BY created_at DESC LIMIT 1[0m [["user_id", 1]]
[1m[35mArticle Load (1.0ms)[0m SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? ORDER BY created_at DESC LIMIT 1 [["id", "40"]]
[1m[36m (0.0ms)[0m [1mbegin transaction[0m
[1m[35mPhoto Load (1.0ms)[0m SELECT "photos".* FROM "photos" WHERE "photos"."article_id" = ? AND "photos"."id" IN (132, 133, 134) [["article_id", 40]]
[1m[36m (0.0ms)[0m [1mSELECT COUNT(*) FROM "photos" WHERE "photos"."article_id" = ?[0m [["article_id", 40]]
[1m[35mSQL (1.0ms)[0m DELETE FROM "photos" WHERE "photos"."id" = ? [["id", 132]]
[1m[36mSQL (0.0ms)[0m [1mDELETE FROM "photos" WHERE "photos"."id" = ?[0m [["id", 133]]
[1m[35mSQL (0.0ms)[0m DELETE FROM "photos" WHERE "photos"."id" = ? [["id", 134]]
[1m[36m (4.0ms)[0m [1mcommit transaction[0m
Redirected to http://localhost:3000/users/1
Completed 302 Found in 26ms (ActiveRecord: 7.0ms)
photos table
sqlite> .schema photos
CREATE TABLE "photos" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "articl_id" integer, "image" varchar(255), "created_at" datetime, "updated_at" datetim);
\models\article.rb
# encoding: utf-8
class Article < ActiveRecord::Base
belongs_to :user
belongs_to :category
has_many :photos, dependent: :destroy
accepts_nested_attributes_for :photos, reject_if: :all_blank, allow_destroy: true
default_scope -> { order('created_at DESC') }
validates :content, presence: true, length: { maximum: 140 }
validates :user_id, presence: true
validates :category_id, presence: true
validate :check_for_at_least_image
def build_images
(3 - self.photos.size).times {self.photos.build}
end
def check_for_at_least_image
errors.add(:image, "select...") if self.photos.size <= 0
end
end
\models\photo.rb
class Photo < ActiveRecord::Base
belongs_to :article
mount_uploader :image, ImageUploader
end
\view\articles\edit.html.erb
<div class="row">
<div class="span8">
<%= render 'shared/article_form' %>
</div>
</div>
\view\shared\ _article_form.html.erb
<%= form_for(#article) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.hidden_field :category_id %>
<%= f.fields_for :photos do |p| %>
<%= p.hidden_field :article_id %>
<div class="photo">
<% if p.object.image and p.object.image.file %>
<%= image_tag p.object.image.thumb.url %>
<p>article:<%= #article.id %></p>
<p>photo:<%= p.object.id %></p>
<%= p.hidden_field :image_cache if p.object.image_cache %>
<label><%= p.check_box :_destroy %>delete</label>
<% end %>
<%= p.file_field :image %>
</div>
<% end %>
<%= f.text_area :content, placeholder: "Enter content..." %>
</div>
<%= f.submit class: "btn btn-large btn-primary" %>
<% end %>
\controllers\articles_controller.rb
class ArticlesController < ApplicationController
before_action :signed_in_user, only: [:create, :destroy]
before_action :correct_user, only: [:update, :destroy]
.
.
def new
#article = Article.new
#category = Category.find(params[:category])
#article.category_id = #category.id
3.times { #article.photos.build }
end
def create
#article = current_user.articles.build(article_params)
if #article.save
flash[:success] = "article created!"
redirect_to current_user #root_url
else
#article.build_images
render 'new'
end
end
.
.
def edit
#article = Article.find(params[:id])
#article.build_images
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to current_user
else
render 'edit'
end
end
def destroy
#article.destroy
redirect_to root_url
end
private
def article_params
params.require(:article).permit(:content, :category_id, photos_attributes: [:id, :article_id, :image, :image_cache, :_destroy])
end
.
.
end
Just looked at your question and was thinking that may be your validations are running before the destory call on child objects and searched around a bit and found this post, looks like i was right about validations being run before destory. Just going to post pointer related to your question
The problem here is that accepts_nested_attributes_for call destroy for child objects AFTER validation of the parent object. So the user is able to delete an image. Of course, later, when the user will try to edit an article, he/she will get an error – “Select at least one image.”.
Fix:
accepts_nested_attributes_for :photos, reject_if: proc { |attributes| attributes['image'].blank? } , allow_destroy: true #as discussed in your other question you have to use proc to solve your update problem
validate :check_for_at_least_image
def check_for_at_least_image
errors.add(:image, "select...") if photos.reject(&:marked_for_destruction?).size <= 0
end

Resources