I am trying to re-create a stack overflow like app. One user asks a question, and others can answer. I have a nested form indented on the question's page to get answers from other users.
I am having a difficult time to retrieve the data after the answer is posted, and I have set #answer incorrectly on the questions controller page in the update action, and I can't figure out how to properly retrieve this variable given that the params coming through the questions_controller does not have details of the answer set separately. How do I retrieve the params part related to #answer so that I can set the variable, or maybe I need to use different routes for that?
My form looks like this:
<%= form_for #question do |form| %>
<%=form.fields_for :answer do |answer_form| %>
<div class="form-group">
<%=answer_form.text_area :answer_attributes, placeholder: "Add your answer", rows:10, class:"form-control" %>
<%=answer_form.hidden_field :user_id, value: current_user.id, class:'d-none' %>
<%=answer_form.hidden_field :question_id, value: #question.id %>
</div>
<% end %>
<div>
<%=form.submit 'Post Your Answer', class: 'btn-primary' %>
</div>
<% end %>
My Question model looks like this:
class Question < ApplicationRecord
has_many :answers, dependent: :destroy
belongs_to :user
accepts_nested_attributes_for :answers
validates :headline, presence: true , length: { minimum: 20 }
validates :body, presence: true, length: { minimum: 50 }
validates_associated :answers
end
and the Answer model is:
class Answer < ApplicationRecord
belongs_to :user
belongs_to :question
validates :body, presence: true, length: { minimum: 50 }
end
Questions controller:
class QuestionsController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
before_action :set_question, except: [:index, :new, :create]
def index
#questions = Question.all.order("id DESC")
end
def show
#question = Question.find(params[:id])
#user = User.find(#question.user_id)
#answers = #question.answers
#answer = Answer.new
end
def new
#question = Question.new
#question.answers.new
end
def create
#question = current_user.questions.new(question_params)
if #question.save
flash[:notice] = "You have successfully posted your question"
redirect_to #question
else
#errors = #question.errors.full_messages
render action: :new
end
end
def edit
set_question
#question = Question.find(params[:id])
end
def update
#question = Question.find(params[:id])
#question.update(question_params)
#answer = #question.answers.new(question_params)
#question.answers.first.user_id = current_user.id
if #question.save
flash[:notice] = "You have sucessfully posted your answer"
redirect_to #question
else
redirect_to new_question_answer_path(#answer), flash: { danger: #question.errors.full_messages.join(",")}
end
end
private
def set_question
#question = Question.find(params[:id])
end
def question_params
params.require(:question).permit(:headline, :body, :user_id, :answer, answers_attributes:[:body, :user_id, :question_id])
end
end
Answers controller:
class AnswersController < ApplicationController
before_action :find_question
def index
#answers = #question.answers
#user = User.find(#question.user_id)
end
def show
#answer = Answer.find(params[:id])
#user = User.find(#question.user_id)
end
def new
#answer = Answer.new(:question_id => #question.id)
end
def create
#answer = Answer.new(answer_params)
if #answer.save
flash[:notice] = "You have sucessfully created the answer."
redirect_to(answers_path(#answer, :question_id => #question.id))
else
flash[:alert] = "Failed to save the answer."
#errors = #answer.errors.full_messages
render :new
end
end
def edit
#answer = Answer.find(params[:id])
end
def update
#answer = Answer.find(params[:id])
if #answer.update_attributes(answer_params)
flash[:notice] = "You have sucessfully updated the answer."
redirect_to(answer_path(#answer, :question_id => #question.id))
else
render :edit
end
end
def delete
#answer = Asnwer.find(params[:id])
end
def destroy
#answer = Answer.find(params[:id])
#answer.destroy
flash[:notice] = "Answer was destroyed"
redirect_to(answers_path)
end
private
def answer_params
params.require(:answer).permit(:body, :user_id, :question_id)
end
def find_question
#question = Question.find(params[:question_id])
end
end
My routes file looks like this:
Rails.application.routes.draw do
get 'questions/index'
root to: 'questions#index'
resources :questions do
resources :answers
end
devise_for :users
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
UPDATE: here are the logs from the moment the server was started and the index page displayed to the moment where I go to the questions page and log the answer
rails server
=> Booting Puma
=> Rails 5.2.2 application starting in development
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.12.0 (ruby 2.6.0-p0), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop
Started GET "/questions/11/answers" for 127.0.0.1 at 2019-03-07 16:10:13 +0600
(1.4ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
↳ /Users/irina/.rvm/gems/ruby-2.6.0/gems/activerecord-5.2.2/lib/active_record/log_subscriber.rb:98
Processing by AnswersController#index as HTML
Parameters: {"question_id"=>"11"}
Question Load (0.8ms) SELECT "questions".* FROM "questions" WHERE "questions"."id" = $1 LIMIT $2 [["id", 11], ["LIMIT", 1]]
↳ app/controllers/answers_controller.rb:65
User Load (2.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 3], ["LIMIT", 1]]
↳ app/controllers/answers_controller.rb:6
Rendering answers/index.html.erb within layouts/application
Answer Load (0.9ms) SELECT "answers".* FROM "answers" WHERE "answers"."question_id" = $1 [["question_id", 11]]
↳ app/views/answers/index.html.erb:11
User Load (1.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 3], ["LIMIT", 1]]
↳ app/views/answers/_new.html.erb:7
Rendered answers/_new.html.erb (61.7ms)
Rendered answers/index.html.erb within layouts/application (92.7ms)
[Webpacker] Compiling…
Started GET "/questions/11/answers" for 127.0.0.1 at 2019-03-07 16:10:18 +0600
Processing by AnswersController#index as HTML
Parameters: {"question_id"=>"11"}
Question Load (1.4ms) SELECT "questions".* FROM "questions" WHERE "questions"."id" = $1 LIMIT $2 [["id", 11], ["LIMIT", 1]]
↳ app/controllers/answers_controller.rb:65
User Load (1.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 3], ["LIMIT", 1]]
↳ app/controllers/answers_controller.rb:6
Rendering answers/index.html.erb within layouts/application
Answer Load (1.3ms) SELECT "answers".* FROM "answers" WHERE "answers"."question_id" = $1 [["question_id", 11]]
↳ app/views/answers/index.html.erb:11
User Load (1.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 3], ["LIMIT", 1]]
↳ app/views/answers/_new.html.erb:7
Rendered answers/_new.html.erb (9.3ms)
Rendered answers/index.html.erb within layouts/application (18.5ms)
Completed 200 OK in 133ms (Views: 108.3ms | ActiveRecord: 18.4ms)
[Webpacker] Compilation failed:
Hash: 53a953077891e4cef2e8
Version: webpack 3.12.0
Time: 2928ms
Asset Size Chunks Chunk Names
application-c57a289721a93641de38.js 3.1 kB 0 [emitted] application
application-c57a289721a93641de38.js.map 2.49 kB 0 [emitted] application
manifest.json 142 bytes [emitted]
[0] ./app/javascript/packs/application.js 346 bytes {0} [built] [failed] [1 error]
ERROR in ./app/javascript/packs/application.js
Module build failed: SyntaxError: Unexpected token (14:15)
12 | if(window.railsEnv && window.railsEnv === 'development'){
13 | try {
> 14 | render(<App />, reactElement)
| ^
15 | } catch (e) {
16 | render(<RedBox error={e} />, reactElement)
17 | }
Completed 200 OK in 11715ms (Views: 11626.9ms | ActiveRecord: 27.7ms)
Started PATCH "/questions/11" for 127.0.0.1 at 2019-03-07 16:10:41 +0600
Processing by QuestionsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"q7HQt4uGPwBIIz0icswfJLWMRk6MiopIfWu9JBcjkuX1VpGBdwlwZu903NDuebSaX8Y90VHnvcEoaV8unV2zkw==", "question"=>{"answer"=>{"answer_attributes"=>"This is the test answer to see how the information goes through", "user_id"=>"3", "question_id"=>"11"}}, "commit"=>"Post Your Answer", "id"=>"11"}
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 3], ["LIMIT", 1]]
↳ /Users/irina/.rvm/gems/ruby-2.6.0/gems/activerecord-5.2.2/lib/active_record/log_subscriber.rb:98
Question Load (0.5ms) SELECT "questions".* FROM "questions" WHERE "questions"."id" = $1 LIMIT $2 [["id", 11], ["LIMIT", 1]]
↳ app/controllers/questions_controller.rb:55
CACHE Question Load (0.0ms) SELECT "questions".* FROM "questions" WHERE "questions"."id" = $1 LIMIT $2 [["id", 11], ["LIMIT", 1]]
↳ app/controllers/questions_controller.rb:39
Unpermitted parameter: :answer
(0.5ms) BEGIN
↳ app/controllers/questions_controller.rb:40
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 3], ["LIMIT", 1]]
↳ app/controllers/questions_controller.rb:40
Answer Load (0.5ms) SELECT "answers".* FROM "answers" WHERE "answers"."question_id" = $1 [["question_id", 11]]
↳ app/controllers/questions_controller.rb:40
(0.3ms) COMMIT
↳ app/controllers/questions_controller.rb:40
Unpermitted parameter: :answer
(0.3ms) BEGIN
↳ app/controllers/questions_controller.rb:44
CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 3], ["LIMIT", 1]]
↳ app/controllers/questions_controller.rb:44
(0.4ms) ROLLBACK
↳ app/controllers/questions_controller.rb:44
Completed 500 Internal Server Error in 97ms (ActiveRecord: 8.3ms)
ActionController::UrlGenerationError (No route matches {:action=>"new", :controller=>"answers", :question_id=>nil}, missing required keys: [:question_id]):
app/controllers/questions_controller.rb:48:in `update'
UPDATE NO 2. It looks like because of this falsely set #answer the #question does not get saved as intended and the second part of the conditional kicks redirecting to the new_question_answer_path. I tried to update it to edit_question_answer_path and it gives the same error that no route matches.
If I open the answer in Pry I get the following object:
[1] pry(#<QuestionsController>)> #answer
=> #<Answer:0x00007fc3ec823c98
id: nil,
body: nil,
question_id: 11,
user_id: 3,
selected: nil,
created_at: nil,
updated_at: nil>
UPDATE No 3
Looks like changing my routes.rb to
Rails.application.routes.draw do
resources :questions, :has_many => :answers
root to: 'questions#index'
resources :questions do
resources :answers
end
devise_for :users
end
and also changing the form for the answer to this
<h2> Your Answer </h2>
<%= form_for [#question, Answer.new] do |form| %>
<div class="form-group">
<%=form.text_area :body, placeholder: "Add your answer", rows:10, class:"form-control" %><br>
<%=form.hidden_field :user_id, value: current_user.id, class:'d-none' %>
<%=form.hidden_field :question_id, value: #question.id %>
</div>
<div>
<%=form.submit 'Post Your Answer', class: 'btn-primary' %>
</div>
<% end %>
did the trick and helped to fix the problem. I am not sure if this is a perfect fix though)
Looks like changing my routes.rb to
Rails.application.routes.draw do
resources :questions, :has_many => :answers
root to: 'questions#index'
resources :questions do
resources :answers
end
devise_for :users
end
and also changing the form for the answer to this
<%= form_for [#question, Answer.new] do |form| %>
<div class="form-group">
<%=form.text_area :body, placeholder: "Add your answer", rows:10,
class:"form-control" %><br>
<%=form.hidden_field :user_id, value: current_user.id, class:'d-none' %>
<%=form.hidden_field :question_id, value: #question.id %>
</div>
<div>
<%=form.submit 'Post Your Answer', class: 'btn-primary' %>
</div>
<% end %>
did the trick and helped to fix the problem. I am not sure if this is a perfect fix though)
Related
I am sending an AJAX request from my frontend to rails for a patch request but getting an action cannot be found error.
So far, I have double checked my routes and controller to make sure there were no mistakes. My create action is working fine which is in the users controller. Ive also double checked my AJAX request to make sure it is going to the correct url. My AJAX request is also for an AWS upload if that helps.
Here are my routes
namespace :api, defaults: {format: :json} do
resources :users, only: [:create, :update, :show]
resource :session, only: [:create, :destroy, :show]
end
root "static_pages#root"
end
here is my controller with the update action
class Api::UsersController < ApplicationController
def create
#user = User.new(user_params)
if #user.save
login(#user)
render "api/users/show"
else
render json: #user.errors.full_messages, status: 422
end
def show
#user = User.find(params[:id])
render "api/users/show"
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
render "api/users/show"
else
render json: #user.errors.full_messages
end
end
end
def user_params
params.require(:user).permit(:email, :password, :first_name, :last_name, :DOB, :gender, :prof_photo, :cover_photo)
end
end
Update: ajax request for AWS user photo upload.
export const updateUser = (userId, formData) => {
return $.ajax({
method: "PATCH",
url: `api/users/${userId}`,
data: formData,
contentType: false,
processData: false
})
}
Finally here are the server logs
AbstractController::ActionNotFound - The action 'update' could not be found for Api::UsersController:
Started GET "/" for ::1 at 2019-10-06 07:49:03 -0400
Processing by StaticPagesController#root as HTML
Rendering static_pages/root.html.erb within layouts/application
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."session_token" = $1 LIMIT $2 [["session_token", "mRbshUiTIXjVd3LpZSiWvA"], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:10
ActiveStorage::Attachment Load (0.7ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4 [["record_id", 2], ["record_type", "User"], ["name", "prof_photo"], ["LIMIT", 1]]
↳ app/views/api/users/_user.json.jbuilder:3
ActiveStorage::Blob Load (1.1ms) SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
↳ app/views/api/users/_user.json.jbuilder:3
Rendered api/users/_user.json.jbuilder (7.2ms)
Rendered static_pages/root.html.erb within layouts/application (13.8ms)
Completed 200 OK in 93ms (Views: 86.5ms | ActiveRecord: 2.8ms)
Started PATCH "/api/users/2" for ::1 at 2019-10-06 07:55:37 -0400
AbstractController::ActionNotFound - The action 'update' could not be found for Api::UsersController:````
Found the rookie mistake! The end statement for create action was all the way at the bottom (hence only my create action was working) Make sure to check your end statements!
I am currently building a application where I have a Book Model.
It works locally without any problems at all. I deployed it to Heroku and ran rake db:migrate and tried to create a book
I got following ROLLBACK error.
2018-03-29T07:29:59.748305+00:00 app[web.1]: D, [2018-03-29T07:29:59.748238 #4] DEBUG -- : [feda9269-2f19-4916-a87f-bc179fd52bec] User Load (1.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 3], ["LIMIT", 1]]
2018-03-29T07:29:59.750826+00:00 app[web.1]: D, [2018-03-29T07:29:59.750763 #4] DEBUG -- : [feda9269-2f19-4916-a87f-bc179fd52bec] (0.8ms) BEGIN
2018-03-29T07:29:59.763631+00:00 app[web.1]: D, [2018-03-29T07:29:59.763526 #4] DEBUG -- : [feda9269-2f19-4916-a87f-bc179fd52bec] (0.9ms) ROLLBACK
2018-03-29T07:29:59.764270+00:00 app[web.1]: I, [2018-03-29T07:29:59.764208 #4] INFO -- : [feda9269-2f19-4916-a87f-bc179fd52bec] Rendering books/new.html.erb within layouts/application
2018-03-29T07:29:59.770061+00:00 app[web.1]: I, [2018-03-29T07:29:59.769996 #4] INFO -- : [feda9269-2f19-4916-a87f-bc179fd52bec] Rendered books/_form.html.erb (5.5ms)
2018-03-29T07:29:59.770167+00:00 app[web.1]: I, [2018-03-29T07:29:59.770113 #4] INFO -- : [feda9269-2f19-4916-a87f-bc179fd52bec] Rendered books/new.html.erb within layouts/application (5.8ms)
2018-03-29T07:29:59.771544+00:00 app[web.1]: I, [2018-03-29T07:29:59.771486 #4] INFO -- : [feda9269-2f19-4916-a87f-bc179fd52bec] Rendered layouts/_navbar.html.erb (0.7ms)
2018-03-29T07:29:59.771904+00:00 app[web.1]: I, [2018-03-29T07:29:59.771828 #4] INFO -- : [feda9269-2f19-4916-a87f-bc179fd52bec] Rendered layouts/_alerts.html.erb (0.2ms)
2018-03-29T07:29:59.772181+00:00 app[web.1]: I, [2018-03-29T07:29:59.772125 #4] INFO -- : [feda9269-2f19-4916-a87f-bc179fd52bec] Completed 200 OK in 28ms (Views: 8.2ms | ActiveRecord: 3.4ms)
Books Controller
class BooksController < ApplicationController
before_action :find_book, only: [:show, :edit, :update, :destroy]
before_action :book_owner, only: [:destroy, :edit, :update]
def index
#books = Book.all.order("created_at DESC")
end
def show
end
def new
#book = current_user.books.build
#categories = Category.all.map{ |c| [c.name, c.id] }
end
def create
#book = current_user.books.build(book_params)
#book.category_id = params[:category_id]
if #book.save
redirect_to books_path
else
render 'new'
end
end
def edit
#categories = Category.all.map{ |c| [c.name, c.id] }
end
def update
#book.category_id = params[:category_id]
if #book.update(book_params)
redirect_to book_path(#book)
else
render 'edit'
end
end
def destroy
#book.destroy
redirect_to root_path
end
private
def book_params
params.require(:book).permit(:title, :description, :author, :category_id)
end
def find_book
#book = Book.find(params[:id])
end
def book_owner
unless current_user.id == #book.user_id
flash[:notice] = "You are not allowed to do that!"
redirect_to #book
end
end
end
Book Model
class Book < ApplicationRecord
belongs_to :user
belongs_to :category
end
Book new view
<%= simple_form_for #book, :html => { :multipart => true } do |f| %>
<%= f.input :category_id, collection: #categories, prompt: "Select a category" %>
<%= f.input :title, label: "Book Title" %>
<%= f.input :author %>
<%= f.input :description %>
<%= f.button :submit, :class => "btn-outline-primary" %>
<% end %>
Update:
Started POST "/books" for 127.0.0.1 at 2018-03-29 11:13:22 +0200
Processing by BooksController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"UYKPhHA99zg5TMMwgKGk+h2OPPaCQkpkjohPRnRNQHlJB1eQF4Ooro4Tvx9VDSr3U6/H4AGoThu8jzkrwyMbUB==", "book"=>{"category_id"=>"", "title"=>"tesas", "author"=>"asdasd", "description"=>"asdasd"}, "commit"=>"Create Book"}
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
(0.3ms) ROLLBACK
Rendering books/new.html.erb within layouts/application
Rendered books/_form.html.erb (10.0ms)
Rendered books/new.html.erb within layouts/application (11.9ms)
Rendered layouts/_navbar.html.erb (1.2ms)
Rendered layouts/_alerts.html.erb (0.3ms)
Completed 200 OK in 52ms (Views: 46.3ms | ActiveRecord: 0.7ms)
Category_id is nil because i don't have them set yet on my second laptop because i can't get a Category.connection (Category.create(name: "SOMECATEGORY") using this to create a Category but it won't work without Category.connection)
On my heroku application i was able to do Category.connection and Category.create .. - but even after that it didn't work.
What am I doing wrong? Thanks for your help in advance as always!
You are getting the error because the record is invalid. The reason is you are not properly assigning the category_id.
You need to change params[:category_id] to book_params[:category_id]
params[:category_id] will give you nil and the validation check will fail.
def create
#book = current_user.books.build(book_params)
#book.category_id = book_params[:category_id]
if #book.save
redirect_to books_path
else
render 'new'
end
end
You need to make the same changes for update action as well
Update:
I think i found my error : my user_id was nil when creating via web - i created the same record on console and passed the parameter user_id - voila, works. My user_id parameter somehow don't pass on the heroku rails server but it does on the local machine. No code lines were changed.
How is this even possible?
Help me please. Rails swear...
What should I change? I allowed all parameters (permit_params), but this does not help:
ActiveModel::ForbiddenAttributesError
Extracted source (around line #17):
#user = User.where(id: params[:id]).first_or_create
#user.superadmin = params[:user][:superadmin]
#user.attributes = params[:user].delete_if do |k, v|
(k == "superadmin") ||
(["password", "password_confirmation"].include?(k) && v.empty? && !#user.new_record?)
end
"config.action_controller.permit_all_parameters = true" solves the problem. But I do not want to disable strong_parameters.
UPDATE
app/admin/user.rb
ActiveAdmin.register User do
form do |f|
f.inputs "User Details" do
f.input :email
f.input :password
f.input :password_confirmation
f.input :superadmin, :label => "Super Administrator"
end
f.actions
end
create_or_edit = Proc.new {
#user = User.where(id: params[:id]).first_or_create
#user.superadmin = params[:user][:superadmin]
#user.attributes = params[:user].delete_if do |k, v|
(k == "superadmin") ||
(["password", "password_confirmation"].include?(k) && v.empty? && !#user.new_record?)
end
if #user.save
redirect_to :action => :show, :id => #user.id
else
render active_admin_template((#user.new_record? ? 'new' : 'edit') + '.html.erb')
end
}
member_action :create, :method => :post, &create_or_edit
member_action :update, :method => :put, &create_or_edit
permit_params :authenticity_token, :commit, :id, user: [:email, :password, :password_confirmation, :superadmin]
end
P.S. I worked on this guide.
The problem is very similar to this problem: I get ActiveModel::ForbiddenAttributesError with Active Admin and Devise I get this error when I create a new user in the administration panel ActiveAdmin.
UPDATE1
console
Started POST "/admin/users" for 127.0.0.1 at 2017-12-08 22:57:04 +0300
Processing by Admin::UsersController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"***********", "user"=>{"email"=>"test#test.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "superadmin"=>"0"}, "commit"=>"Create User"}
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
User Load (0.9ms) SELECT "users".* FROM "users" WHERE "users"."id" IS NULL ORDER BY "users"."id" ASC LIMIT $1 [["LIMIT", 1]]
(3.0ms) BEGIN
(0.4ms) ROLLBACK
Completed 500 Internal Server Error in 24ms (ActiveRecord: 5.2ms)
ActiveModel::ForbiddenAttributesError
ActiveModel::ForbiddenAttributesError):
app/admin/user.rb:17:in `block (2 levels) in <top (required)>'
I have to agree with the answer given to the question you referenced, per the doc please try:
permit_params :email, :password, :password_confirmation, :superadmin
I'm using the Best In Place Gem to do inline edits on a table of Tasks that has a nested attribute for Storeorder, however when I try to edit a Storeorder attribute using the instructions provided in this post, I get a 204 No Content error thrown at me. I wonder if it has to do with the first transaction beginning before the 'Storeorder Load' happens? In all non-nested BIP updates, it does the UPDATE within the first "begin transaction" call, whereas here it's still loading the Storeorder. The parameters are 100% correct as far as I can tell. See code,
Started PUT "/tasks/3" for 104.200.151.54 at 2017-02-05 18:08:24 +0000
Processing by TasksController#update as JSON
Parameters: {"task"=>{"storeorder_attributes"=>{"id"=>"3", "activity"=>"Shipped"}}, "authenticity_token"=>"D2c3ddoIC220rkPE5i7U+EGiwSrdCq7s8vdFY8VEQTaTMqetuBo8SJX9+Wabl+Bh6A6d49Pt/Omp4E/nq/udQA==", "id"=>"3"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
Task Load (0.2ms) SELECT "tasks".* FROM "tasks" WHERE "tasks"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
CACHE (0.0ms) SELECT "tasks".* FROM "tasks" WHERE "tasks"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
(0.1ms) begin transaction
Storeorder Load (0.2ms) SELECT "storeorders".* FROM "storeorders" WHERE "storeorders"."task_id" = ? LIMIT ? [["task_id", 3], ["LIMIT", 1]]
(0.1ms) commit transaction
(0.1ms) begin transaction
(0.1ms) commit transaction
Completed 204 No Content in 10ms (ActiveRecord: 1.0ms)
tasks_controller.rb -->
class TasksController < ApplicationController
before_action :set_task, only: [:show, :edit, :update, :destroy]
def update
#task = Task.find(params[:id])
respond_to do |format|
if #task.update(task_params)
format.html { redirect_to #task, notice: 'Task was successfully updated.' }
format.json { respond_with_bip(#task) }
else
format.html { render :edit }
format.json { respond_with_bip(#task) }
end
end
end
private
def set_task
#task = Task.find(params[:id])
end
def task_params
params.require(:task).permit!
end
end
task.rb -->
class Task < ApplicationRecord
has_one :storeorder, :dependent => :destroy
accepts_nested_attributes_for :storeorder, :reject_if => lambda { |a| a[:store_id].blank? }, :allow_destroy => true
end
storeorder.rb -->
class Storeorder < ApplicationRecord
belongs_to :task
end
dashboard.html.erb -->
<td><%= best_in_place task.storeorder, :activity,
url: task_path(task.id),
param: "task[storeorder_attributes][id]=#{task.storeorder.id}&task[storeorder_attributes]",
as: :select,
collection: [["Pending Shipment", "Pending Shipment"], ["Shipped", "Shipped"], ["Cancelled", "Cancelled"], ["Pending Further Action", "Pending Further Action"]], %>
</td>
inner HTML code -->
<span
data-bip-type="select"
data-bip-attribute="activity"
data-bip-collection="[["Pending Shipment","Pending Shipment"],["Shipped","Shipped"],["Cancelled","Cancelled"],["Pending Further Action","Pending Further Action"]]"
data-bip-inner-class="form-control"
data-bip-object="task[storeorder_attributes][id]=3&task[storeorder_attributes]"
data-bip-original-content="Pending Shipment"
data-bip-skip-blur="false"
data-bip-url="/tasks/3"
data-bip-value="Shipped"
class="best_in_place form-control"
id="best_in_place_storeorder_3_activity">
Shipped
</span>
I can't see what I could possibly be missing that causes this error. It's imperative that I'm allowed to do inline edits to keep the workflow consistent, otherwise I'm open to alternative suggestions since I know BIP doesn't have nested attribute editing within their scope by default.
:reject_if => lambda { |a| a[:store_id].blank? }
Don't see any store_id being passed in params.
I am having some difficulty getting my nested rails form to display validation errors in the view
Controller:
class RentersController < ApplicationController
before_action :set_renter, only: [:show, :edit, :update, :destroy]
before_action :get_rental
def get_rental
#rental = Rental.find(params[:rental_id])
end
...
# GET /renters/new
def new
#renter = Renter.new
end
...
def create
#renter = #rental.renters.new(renter_params)
respond_to do |format|
if #renter.save
format.html { redirect_to rental_renters_path(#rental), notice: 'Renters were successfully created.' }
format.json { render :show, status: :created, location: #renter }
else
puts #renter.errors.full_messages
format.html { render :new }
format.json { render json: #renter.errors, status: :unprocessable_entity }
end
end
end
...
end
Model
class Renter < ApplicationRecord
belongs_to :rental
validates :name, presence: { message: "..." }
validates :height, presence: { message: "..." }
validates :weight, presence: { message: "..." }
validates :shoeSize, presence: { message: "..." }
end
_form partial being rendered in View
<div class="rental-forms-container sixteen wide column">
<%= form_for([#rental, #renter], remote: true, :html => { class: "renter-form ui form", id: "base-form" }) do |f| %>
<div class="fields">
...
</div>
<% end %>
</div>
<div class="ui warning message">
...
<ul class="list">
<% #renter.errors.messages.values.each do |message| %>
<% message.each do |m| %>
<li><%= m %></li>
<% end %>
<% end %>
</ul>
</div>
...
<%= link_to 'continue with booking', rental_renters_path, remote: true, class: 'ui teal submit button', id: 'submitRenterForms' %>
</div>
Console
Processing by RentersController#create as JS
Processing by RentersController#index as JS
Parameters: {"utf8"=>"✓", "renter"=>{"name"=>"", "height"=>"", "weight"=>"", "wetsuit_style"=>"Adult Womens", "shoeSize"=>"", "rental_id"=>""}, "rental_id"=>"109"}
Parameters: {"rental_id"=>"109"}
Rental Load (0.3ms) SELECT "rentals".* FROM "rentals" WHERE "rentals"."id" = $1 LIMIT $2 [["id", 109], ["LIMIT", 1]]
Rental Load (5.5ms) SELECT "rentals".* FROM "rentals" WHERE "rentals"."id" = $1 LIMIT $2 [["id", 109], ["LIMIT", 1]]
(0.2ms) BEGIN
(0.1ms) ROLLBACK
Name Let us know the name of each renter so we can customize your experience
Height Let us know the height of each renter so we can properly size your wetsuits
Weight Let us know the weight of each renter so we can properly size your wetsuits
Shoesize Let us know the shoe size of each renter so everyone gets the right surf booties
Rendering renters/new.html.erb within layouts/application
Rendered renters/_form.html.erb (2.4ms)
Rendered renters/new.html.erb within layouts/application (3.7ms)
Rendered shared/_following_menu.html.erb (0.1ms)
Rendered shared/_sidebar_menu.html.erb (0.1ms)
Rendered shared/_menu.html.erb (0.8ms)
Rendered shared/_footer.html.erb (0.5ms)
Completed 200 OK in 106ms (Views: 73.8ms | ActiveRecord: 14.0ms)
(0.6ms) SELECT COUNT(*) FROM "renters" WHERE "renters"."rental_id" = $1 [["rental_id", 109]]
Rendering renters/index.html.erb within layouts/application
Charge Load (0.3ms) SELECT "charges".* FROM "charges" WHERE "charges"."rental_id" = $1 LIMIT $2 [["rental_id", 109], ["LIMIT", 1]]
Rendered rentals/_info.html.erb (11.0ms)
Renter Load (0.3ms) SELECT "renters".* FROM "renters" WHERE "renters"."rental_id" = $1 [["rental_id", 109]]
Rendered charges/_form.html.erb (1.9ms)
Rendered renters/index.html.erb within layouts/application (37.5ms)
Rendered shared/_following_menu.html.erb (0.6ms)
Rendered shared/_sidebar_menu.html.erb (0.5ms)
Rendered shared/_menu.html.erb (1.2ms)
Rendered shared/_footer.html.erb (1.4ms)
Completed 200 OK in 265ms (Views: 134.5ms | ActiveRecord: 9.5ms)
The validation errors are outputting to the terminal but they are not appearing in the view.
I have tried using the flash and session hashes to pass them to the view but to no avail. Any guidance would be greatly appreciated.
When using form_for (or if you're now using form_with) pay attention to whether remote or local is set to true. Local uses the browser's normal submission mechanism, while remote uses Ajax. When using remote (as indicated above), the page will not render in the "normal" fashion, as expected.
The Rails documentation has more details: http://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html