M:N relation error in Rails - ruby-on-rails

i got some error when trying to make relation between Post and Hashtag by m : n
all things fine but when try to save log prints like this
Started POST "/posts" for 127.0.0.1 at 2018-03-05 21:43:00 +0900
Processing by PostsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"DxRb+4PAfOsDTCEMx+BcBNKK/LWAH5NxwVh6n7OChtwBL/svUQVEBj7mrWdCYB2BIUHO/Gql9UC6mKLMMoPqEg==", "post"=>{"title"=>"please", "content"=>"please!!!!!", "hashtags_attributes"=>{"0"=>{"title"=>"hash1"}, "1"=>{"title"=>"hash2"}, "2"=>{"title"=>"hash3"}}}, "commit"=>"Create Post"}
Unpermitted parameter: hashtags_attributes
Unpermitted parameters: title, content
Hashtag Load (0.2ms) SELECT "hashtags".* FROM "hashtags" WHERE "hashtags"."title" = ? LIMIT ? [["title", "hash1"], ["LIMIT", 1]]
Unpermitted parameters: title, content
Hashtag Load (0.1ms) SELECT "hashtags".* FROM "hashtags" WHERE "hashtags"."title" = ? LIMIT ? [["title", "hash2"], ["LIMIT", 1]]
Unpermitted parameters: title, content
Hashtag Load (0.1ms) SELECT "hashtags".* FROM "hashtags" WHERE "hashtags"."title" = ? LIMIT ? [["title", "hash3"], ["LIMIT", 1]]
(0.0ms) begin transaction
SQL (0.3ms) INSERT INTO "posts" ("title", "content", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["title", "please"], ["content", "please!!!!!"], ["created_at", "2018-03-05 12:43:00.937624"], ["updated_at", "2018-03-05 12:43:00.937624"]]
SQL (0.1ms) INSERT INTO "hashtags_posts" ("hashtag_id", "post_id") VALUES (?, ?) [["hashtag_id", 1], ["post_id", 2]]
(0.3ms) rollback transaction
Completed 500 Internal Server Error in 12ms (ActiveRecord: 1.4ms)
ActiveModel::MissingAttributeError (can't write unknown attribute `id`):
app/controllers/posts_controller.rb:36:in `block in create'
app/controllers/posts_controller.rb:35:in `create'
Rendering /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout
Rendering /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_source.html.erb
Rendered /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_source.html.erb (7.4ms)
Rendering /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
Rendered /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (2.0ms)
Rendering /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
Rendered /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.1ms)
Rendered /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/actionpack-5.0.6/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (124.9ms)
i don't know why title content, and hashtags_attributes are unpermitted parameters. i set them in white list correctly
this is my codes
posts_controller.rb
def create
#post = Post.new(post_params)
3.times do |x|
tag = hashtag_params[:hashtags_attributes]["#{x}"]["title"]
a = Hashtag.find_or_create_by(title: tag)
#post.hashtags << a
end
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def hashtag_params
params.require(:post).permit(hashtags_attributes: [:title])
end
this is my post.rb
class Post < ApplicationRecord
has_and_belongs_to_many :hashtags
accepts_nested_attributes_for :hashtags
end
this is my hashtag.rb
class Hashtag < ApplicationRecord
has_and_belongs_to_many :posts
end
At last, my _form.html.erb
<%= form_for(post) do |f| %>
<% if post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% post.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :content %>
<%= f.text_area :content %>
</div>
<div class="field">
<%= f.fields_for :hashtags do |h|%>
<%=h.label :title, "해시태그"%>
<%=h.text_field :title%>
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

You only need to specify post_params correctly:
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def post_params
params.require(:post).permit(:title, :content, hashtags_attributes: [:id, :title])
end
You can read more here
And you need to change your migration
class CreateJoinTableHashtagsPosts < ActiveRecord::Migration[5.0]
def change
create_join_table :hashtags, :posts do |t|
t.index :hashtag_id
t.index :post_id
end
end
end
After it you need to run rake db:rollback && rake db:migrate.
Or you can use rake db:drop && rake db:create && rake db:migrate to recreate db from scratch, in this case you lose all existing data

Related

Unpermitted parameters: :utf8, :authenticity_token - Rails 5.2 form_with

I'm ripping my hair out with this one. I am getting an unpermitted params on a form_with with a nested resource. I am using Rails 5.2.1 and Ruby 2.5.
I am not sure where in the world I am going wrong with this. I have tried all sorts of variations of site_params but to no luck. Any help would be appreciated.
Here's my routes.rb:
resources :locations do
post 'sites', to: 'sites#custom_create', as: :site_custom
resources :sites, except: [:edit, :update, :show]
end
And the relevant Controller Functions:
def new
verify_site_name or return
#site = #location.sites.new
authorize #site
#available_site = AvailableSite.find_by(site_name: params[:site_name])
#finder_results = get_finder_results([:site_name], #location)
end
def create
verify_site_name or return
#site = #location.sites.new(site_params)
authorize #site
respond_to do |format|
if #site.save
format.html { redirect_to location_sites_path, notice: 'Location was successfully created.' }
format.json { render :show, status: :created, site: #site }
else
format.html { redirect_to location_sites_path, alert: "#{#site.errors.full_messages.first}" }
format.json { render json: #site.errors, status: :unprocessable_entity }
end
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def site_params
params.permit(:location_id, :place_id, :site_name, :review_url)
end
# Use callbacks to share common setup or constraints between actions.
def set_site
#site = Site.find(params[:id])
end
def set_location
#location = Location.friendly.find(params[:location_id])
end
And of course, the form itself:
<%= form_with(model: [#location, #site], local: true, class: 'site-form') do |form| %>
<%= hidden_field_tag(:site_name, #available_site.site_name) %>
<div class="field md:w-3/4 lg:w-2/3 mx-auto text-left">
<%= form.text_field :review_url, class: 'text-input', placeholder: 'https://www.facebook.com/yourbusinessname/review/?ref=page_internal' %>
<span class="form-required">*required</span>
</div>
<%= form.submit "Manually Submit #{#available_site.site_name.titleize}", class: 'btn btn-green btn-outline' %>
<% end %>
And lastly, the log:
Started POST "/locations/tekamar-mortgages-ltd/sites" for 127.0.0.1 at 2018-12-03 15:30:57 +0000
Processing by SitesController#custom_create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"l/DjkUbVNyw+nrXxo1B/9IGru043Ftroxy8FcuNcZuxmJ7V3j0gC8njm5kpGPT8c7tMWSaAR/ler3cSHY+t8aA==", "site"=>{"site_name"=>"google", "review_url"=>"https://www.yelp.ca/biz/your-busines-sname?utm_campaign=www_business_share_popup&utm_medium=copy_link&utm_source=(direct)"}, "commit"=>"Create Site", "location_id"=>"tekamar-mortgages-ltd"}
Location Load (0.8ms) SELECT "locations".* FROM "locations" WHERE "locations"."slug" = $1 LIMIT $2 [["slug", "tekamar-mortgages-ltd"], ["LIMIT", 1]]
↳ app/controllers/sites_controller.rb:78
User Load (1.9ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
↳ /Users/richsmith/.rvm/gems/ruby-2.5.1/gems/activerecord-5.2.1/lib/active_record/log_subscriber.rb:98
Unpermitted parameters: :utf8, :authenticity_token, :site, :commit
Redirected to http://localhost:3000/locations/tekamar-mortgages-ltd/sites
Completed 302 Found in 13ms (ActiveRecord: 2.6ms)
Try:
def site_params
params.require(:site).permit(:location_id, :place_id, :site_name, :review_url)
end
Params for site are nested in params[:site]. You should first take this hash out of all the params, and then call permit on it. Right now you're sanitizing all the params (that include some stuff you're clearly not interested in, as utf8 or authenticity_token).

Rails 5 Independent View Nested Resource - param is missing or the value is empty

I have a nested resource called PracticeQuestion, which is a child of PracticeQuiz. I want users to be able to go through one question at a time when they are at a PracticeQuiz. For example: foo.com/practice_quizzes/1/practice_questions/1..n
I got the practice quizzes working, but when I try to add a new practice question, I get a rails error that says that the param is missing or empty, but I don't see what i'm doing wrong. Please help
practice_quiz.rb
class PracticeQuiz < ApplicationRecord
belongs_to :user, optional: true
validates :user, presence: true
has_many :practice_questions, dependent: :destroy
end
practice_question.rb
class PracticeQuestion < ApplicationRecord
belongs_to :user, optional: true
belongs_to :practice_quiz
end
practice_questions_controller.rb
class PracticeQuestionsController < ApplicationController
before_action :set_practice_question, only: [:show, :edit, :update, :destroy]
def index
#practice_questions = PracticeQuestion.all
end
def show
end
# GET /practice_questions/new
def new
#practice_quiz = PracticeQuiz.friendly.find(params[:practice_quiz_id])
#practice_question = PracticeQuestion.new
end
# GET /practice_questions/1/edit
def edit
end
def create
#practice_quiz = PracticeQuiz.friendly.find(params[:practice_quiz_id])
#practice_question = PracticeQuestion.new(practice_question_params)
respond_to do |format|
if #practice_question.save
format.html { redirect_to #practice_question, notice: 'Practice question was successfully created.' }
format.json { render :show, status: :created, location: #practice_question }
else
format.html { render :new }
format.json { render json: #practice_question.errors, status: :unprocessable_entity }
end
end
end
private
def set_practice_question
#practice_question = PracticeQuestion.find(params[:id])
end
def practice_question_params
params.require(:practice_question).permit(:question, :explanation, :flagged)
end
end
views/practice_questions/_form.html.erb
<%= form_with(url: practice_quiz_practice_questions_path, local: true) do |form| %>
<% if practice_question.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(practice_question.errors.count, "error") %> prohibited this practice_question from being saved:</h2>
<ul>
<% practice_question.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :question %>
<%= form.text_field :question %>
</div>
<div class="field">
<%= form.label :explanation %>
<%= form.text_field :explanation %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
routes.rb
resources :practice_quizzes do
resources :practice_questions
end
I set the practice_questions controller's new method to find the id of the parent resource, but I get this error. I'm pretty sure I'm following rails naming conventions fine too.
ActionController::ParameterMissing at /practice_quizzes/23535/practice_questions
param is missing or the value is empty: practice_question
Update: here's the results from the rails server window
Processing by PracticeQuestionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"7dpxBB7jjZWzicCYWGA8yeTPSc9UeaqNDOavKQai2vMISryPBiMZ9Zo4LLS3DgZQI8IJc7rLh2TXd9Fj8PAjiA==", "question"=>"235235", "explanation"=>"25235232", "commit"=>"Save ", "practice_quiz_id"=>"23535"}
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
PracticeQuiz Load (0.9ms) SELECT "practice_quizzes".* FROM "practice_quizzes" WHERE "practice_quizzes"."slug" = $1 ORDER BY "practice_quizzes"."id" ASC LIMIT $2 [["slug", "23535"], ["LIMIT", 1]]
Completed 400 Bad Request in 102ms (ActiveRecord: 1.7ms)
ActionController::ParameterMissing - param is missing or the value is empty: practice_question:
app/controllers/practice_questions_controller.rb:76:in `practice_question_params'
app/controllers/practice_questions_controller.rb:30:in `create'
Update 2:
views/practice_questions/new.html.erb
<h1>New Practice Question</h1>
<%= render 'form', practice_question: #practice_question %>
Here
def practice_question_params
params.require(:practice_question).permit(:question, :explanation, :flagged)
end
you are using rails strong parameters. See this answer https://stackoverflow.com/a/30826895/2627121
Basically, params.require(:practice_question) means that you must have practice_question parameter.
Here
Parameters: {"utf8"=>"✓", "authenticity_token"=>"", "question"=>"235235", "explanation"=>"25235232", "commit"=>"Save ", "practice_quiz_id"=>"23535"}
you have question and explanation as root parameters, when according to your strong parameters declaration you must have
"practice_question" => { "question"=>"235235", "explanation"=>"25235232" }
You should edit form fields to have name as practice_question[question]

How to manually save a reference object in Rails

Edit: Main problem was that when I added the reference fields, I did theater:reference and not theater:references so the field was not marked as a foreign key. Once I undid those migrations and redid them correctly, I was able to make this work.
In my showtimes controller, I am trying to automatically set the theater id to whatever theater owns the screen that the user inputed, but when I try to save it as an integer or a string, I get an error. Yet, when I try to save it as a theater object, I get "Unpermitted parameter: theater" from the console and a "Theater must exist" error from the rails application.
showtimes_controller:
class ShowtimesController < ApplicationController
before_action :set_theater, only: [:create, :edit]
before_action :set_showtime, only: [:show, :edit, :update, :destroy]
# GET /showtimes
# GET /showtimes.json
def index
#showtimes = Showtime.all
end
# GET /showtimes/1
# GET /showtimes/1.json
def show
end
# GET /showtimes/new
def new
#showtime = Showtime.new
end
# GET /showtimes/1/edit
def edit
end
# POST /showtimes
# POST /showtimes.json
def create
#showtime = Showtime.new(showtime_params)
respond_to do |format|
if #showtime.save
format.html { redirect_to #showtime, notice: 'Showtime was successfully created.' }
format.json { render :show, status: :created, location: #showtime }
else
format.html { render :new }
format.json { render json: #showtime.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /showtimes/1
# PATCH/PUT /showtimes/1.json
def update
respond_to do |format|
if #showtime.update(showtime_params)
format.html { redirect_to #showtime, notice: 'Showtime was successfully updated.' }
format.json { render :show, status: :ok, location: #showtime }
else
format.html { render :edit }
format.json { render json: #showtime.errors, status: :unprocessable_entity }
end
end
end
# DELETE /showtimes/1
# DELETE /showtimes/1.json
def destroy
#showtime.destroy
respond_to do |format|
format.html { redirect_to showtimes_url, notice: 'Showtime was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_showtime
#showtime = Showtime.find(params[:id])
end
def set_theater
screenInfo = Screen.where("id = ?", params[:showtime][:screen])
params['showtime']['theater'] = Theater.find(screenInfo[0]['theater_id'])
end
# Never trust parameters from the scary internet, only allow the white list through.
def showtime_params
params.require(:showtime).permit(:date, :time, :archived, :movie_id, :theater, :screen)
end
end
showtimes model:
class Showtime < ApplicationRecord
belongs_to :movie
belongs_to :theater
end
Showtimes _form
<%= form_for(showtime) do |f| %>
<% if showtime.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(showtime.errors.count, "error") %> prohibited this showtime from being saved:</h2>
<ul>
<% showtime.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :date %>
<%= f.date_select :date %>
</div>
<div class="field">
<%= f.label :time %>
<%= f.time_select :time %>
</div>
<div class="field">
<%= f.label :archived %>
<%= f.check_box :archived %>
</div>
<div class="field">
<%= f.label :movie_id %>
<%= f.text_field :movie_id %>
</div>
<div class="field">
<%= f.label :screen %>
<%= f.text_field :screen %>
</div>
<%= f.hidden_field :theater, :value => "" %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Error when trying to save as integer:
Theater(#70015922237640) expected, got Fixnum(#11723820)
Error when trying to save as string:
Theater(#70015868755420) expected, got String(#11739240)
Logs when trying to save as Theater object:
Started POST "/showtimes" for IP at 2016-11-08 20:22:37 +0000
Processing by ShowtimesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"nENPV5d6YRXdcx3H+Xa9ZypGtyFlaTg+zyENGB10TmW9OyWxLR9Dsl7nDoG9irq+3qApiNA2/oEqL5RZ0SXorA==", "showtime"=>{"date(1i)"=>"2016", "date(2i)"=>"11", "date(3i)"=>"8", "time(1i)"=>"2016", "time(2i)"=>"11", "time(3i)"=>"8", "time(4i)"=>"20", "time(5i)"=>"22", "archived"=>"0", "movie_id"=>"2", "screen"=>"1", "theater"=>""}, "commit"=>"Create Showtime"}
[1m[36mScreen Load (0.3ms)[0m [1m[34mSELECT "screens".* FROM "screens" WHERE (id = '1')[0m
[1m[36mTheater Load (0.2ms)[0m [1m[34mSELECT "theaters".* FROM "theaters" WHERE "theaters"."id" = ? LIMIT ?[0m [["id", 1], ["LIMIT", 1]]
Unpermitted parameter: theater
[1m[35m (0.1ms)[0m [1m[36mbegin transaction[0m
[1m[36mMovie Load (0.2ms)[0m [1m[34mSELECT "movies".* FROM "movies" WHERE "movies"."id" = ? LIMIT ?[0m [["id", 2], ["LIMIT", 1]]
[1m[35m (0.2ms)[0m [1m[31mrollback transaction[0m
Rendering showtimes/new.html.erb within layouts/application
Rendered showtimes/_form.html.erb (13.6ms)
Rendered showtimes/new.html.erb within layouts/application (16.4ms)
Completed 200 OK in 323ms (Views: 86.5ms | ActiveRecord: 3.9ms)
How the hell do I save this parameter?
Have you tried assigning your object to an instance variable, and assigning it before saving?
On your before_action
def set_theater
#theather = ... # Code to find the theather
end
On your create action
def create
#showtime = Showtime.new(showtime_params)
#showtime.theather = #theather
... # Code to save and handle errors
end
You use theater instead of theater_id in several places in your code, and you'll need to change it in all the places, in order for this to work.
Firstly - you can't select a theater in our form... html doesn't recognise a type of theaterand will not pass one through - so your form needs to pass the theater_id instead (which will be an integer that it happily can deal with).
# eg here make sure it's a theater_id
<%= f.hidden_field :theater_id, :value => #theater.id %>
next - your require/permit is probably what's throwing some errors - you need that to be theater_id as well:
def showtime_params
params.require(:showtime).permit(:date, :time, :archived, :movie_id, :theater_id, :screen)
end
Now you need to fetch the theater out, using the screen-info param - but also keep in mind that this might come through as nil some times (so a guard-clause is always good):
def set_theater
if params[:showtime].present? && params[:showtime][:screen_id].present?
screen_info = Screen.find(params[:showtime][:screen_id])
#theater = Theater.find(screenInfo.theater_id)
end
end
Note: I have updated naming-schemes to be rail-standard and removed the thing where you try to set the theatre in params as below:
params['showtime']['theater'] = Theater.find(screenInfo[0]['theater_id'])
I don't know what you're actually trying to do with this line of code, but whatever it is, params doesn't work that way - consider that params is "the set of things that were passed through to us from the user, and are then thrown away" - we don't use it to store new values that we create ion the controller. That's what #variables are for
Can you explain more what you're trying to do and we'll figure out the right way to do it :)

Model instances not flagged as changed after successful attribute update

I would like to do conditionally show/hide some elements in one of my views depending on if a #project.update changed attributes or not.
I am trying to understand WHY my model instances are not being marked as changed after a successful attribute update.
It appears that ActiveModel::Dirty is not properly indicating my model's attributes have changed or more likely I'm not using it properly.
Here is an annotated log of a PATCH request I make to my ProjectController#update action. In it you will see that the attributes change but the model instance does not reflect it. For what it's worth, the controller was generated by a Rails scaffold operation. There's nothing out of the ordinary.
#
# FORM SUBMITTED FROM BROWSER WITH A CHANGE TO THE ATTRIBUTE NAMED "title"
#
Started PATCH "/projects/2" for 127.0.0.1 at 2016-04-23 15:47:38 -0700
Processing by ProjectsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0JH/fEKx+Qk6mOY+eVTteKQUKrZUVXroKzMxuztrTzE/voI+PtzmQnJLGVM5bgdmzJyHDpAon3dzcvvjJ3yEtQ==", "project"=>{"title"=>"changed"}, "commit"=>"Update Project", "id"=>"2"}
Project Load (0.1ms) SELECT "projects".* FROM "projects" WHERE "projects"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
#
# DEBUGGER KICKS IN BEFORE THE UPDATE HAS HAPPENED
#
[40, 49] in app/controllers/projects_controller.rb
40:
41: # PATCH/PUT /projects/1
42: # PATCH/PUT /projects/1.json
43: def update
44: byebug
=> 45: respond_to do |format|
46: if #project.update(project_params)
47: format.html { redirect_to #project, notice: 'Project was successfully updated.' }
48: format.json { render :show, status: :ok, location: #project }
49: else
#
# PROJECT TITLE IS STILL UNMOLESTED
#
(byebug) #project
<Project id: 2, title: "ORIGINAL_TITLE", created_at: "2016-04-23 22:47:30", updated_at: "2016-04-23 22:47:30">
# PROVE PARAMS CONTAIN A CHANGED ATTRIBUTE
(byebug) project_params
<ActionController::Parameters {"title"=>"changed"} permitted: true>
#
# TRIGGER UPDATE AND PERSIST NEW TITLE
#
(byebug) #project.update(project_params)
(0.2ms) begin transaction
SQL (0.9ms) UPDATE "projects" SET "title" = ?, "updated_at" = ? WHERE "projects"."id" = ? [["title", "changed"], ["updated_at", 2016-04-23 22:48:13 UTC], ["id", 2]]
(3.5ms) commit transaction
true
#
# WAT?
#
(byebug) #project.changes
{}
(byebug) #project.changed?
false
(bye bug)
Here is my ProjectsController#update action (standard Rails scaffold):
# app/controllers/projects_controller.rb
# PATCH/PUT /projects/1
# PATCH/PUT /projects/1.json
def update
byebug
respond_to do |format|
if #project.update(project_params)
format.html { redirect_to #project, notice: 'Project was successfully updated.' }
format.json { render :show, status: :ok, location: #project }
else
format.html { render :edit }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
The corresponding view form (also from generated scaffolding):
# app/views/projects/_form.html.erb
<%= form_for(project) do |f| %>
<% if project.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(project.errors.count, "error") %> prohibited this project from being saved:</h2>
<ul>
<% project.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
It seems like you are trying to achieve something if there were any changes made during an update.
If that's the case, you could do something like this :
Use a after_save or after_update callback as necessary for the model and within your callback, if you check self.changes or self.changed? you'd get expected results.

Using cocoon gem, but can't save data after first input field

I've tried to implement cocoon in my application, but having trouble saving data after the first input field.
I tried following the example, but no luck.
I'm able to save the first field into database, but nothing happens on the other fields when I add more.
_form.html.erb
<%= simple_form_for(#project) do |f| %>
<%= f.input :project_name %>
<%= f.hidden_field :user_id %>
<div id="tasks">
<%= f.simple_fields_for :tasks do |g| %>
<%= render 'task_fields', :f => g %>
<% end%>
<%= link_to_add_association 'add task', f, :tasks %>
</div>
<%= f.button :submit %>
<% end %>
_task_fields.html.erb
<li class="control-group nested-fields">
<div class="controls">
<%= f.label :task %>
<%= f.text_field :task %>
</div>
<%= link_to_remove_association "remove task", f %>
</li>
Controller
params.require(:project).permit(
:user_id, :project_name,
tasks_attributes: [:id, :task, :_destroy])
And I added:
//= require cocoon
in application.js
Project Model
class Project < ActiveRecord::Base
belongs_to :user
has_many :tasks
accepts_nested_attributes_for :tasks, :reject_if => :all_blank, allow_destroy: true
end
Task Model
class Task < ActiveRecord::Base
belongs_to :project
end
I think I got this correct? I'm able to click on "add task" link and a new field pops up, but those new fields doesn't save.
EDIT from POST in console
Processing by ProjectsController#create as HTML
Parameters: {
"utf8"=>"✓",
"authenticity_token"=>"blah",
"project"=>{"project_name"=>"cocoon test",
"tasks_attributes"=>{
"0"=>{"task"=>"fix this!",
"_destroy"=>"false"
}}},
"commit"=>"Create Project"}
(0.2ms) begin transaction
SQL (1.5ms) INSERT INTO "projects" ("project_name", "created_at", "updated_at") VALUES (?, ?, ?) [["project_name", "cocoon test"], ["created_at", "2015-07-15 03:26:09.444377"], ["updated_at", "2015-07-15 03:26:09.444377"]]
SQL (0.4ms) INSERT INTO "tasks" ("task", "project_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["task", "fix this!"], ["project_id", 8], ["created_at", "2015-07-15 03:26:09.450324"], ["updated_at", "2015-07-15 03:26:09.450324"]]
(8.4ms) commit transaction
Redirected to http://localhost:3000/projects/8
Completed 302 Found in 24ms (ActiveRecord: 10.4ms)
EDIT 2 posting project controller methods create and new
def create
#project = Project.new(project_params)
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render :show, status: :created, location: #project }
else
format.html { render :new }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
def new
#project = Project.new
#project.tasks.build
end

Resources