Rails - Duplicate record with update action - ruby-on-rails-3

I am having a problem about update action on a basic CRUD controller. This action creates a new record everytime I have called it. I have checked everything a few times and still couldn't figure it out.
post_controller.rb
before_action :find_post, only: [:show, :edit, :update, :destroy]
def edit
end
def update
if #post.update(post_params)
redirect_to #post
else
render 'edit'
end
end
private
def post_params
params.require(:post).permit(:id, :title, :body, :postdate)
end
post.rb
class Post < ActiveRecord::Base
validates :title, presence: true, length: { minimum: 5 }
validates :body, presence: true
validates :postdate, presence: true
def to_param
"#{id} #{title}".parameterize
end
end
Terminal Output just for the requests;
Started GET "/yazilar/new" for ::1 at 2014-12-30 20:03:53 +0200
Processing by PostsController#new as HTML
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
Rendered posts/_form.html.erb (23.9ms)
Rendered posts/new.html.erb within layouts/application (31.6ms)
Completed 200 OK in 257ms (Views: 245.6ms | ActiveRecord: 0.4ms)
Started POST "/yazilar" for ::1 at 2014-12-30 20:04:05 +0200
Processing by PostsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0A3pufznhApS6xDGrfHiVUdhgWO63kD0XGMQ+J/LxJHHsY6N7JtITc0udUjrdYFmvEa49rFzNzmsJ1sbXfM6FQ==", "post"=>{"title"=>"Post_title", "body"=>"<p>Post_body</p>", "postdate(1i)"=>"2014", "postdate(2i)"=>"12", "postdate(3i)"=>"30"}, "commit"=>"Save Post"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
(0.2ms) BEGIN
SQL (18.4ms) INSERT INTO "posts" ("title", "body", "postdate", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["title", "Post_title"], ["body", "<p>Post_body</p>"], ["postdate", "2014-12-30 00:00:00.000000"], ["created_at", "2014-12-30 18:04:05.769804"], ["updated_at", "2014-12-30 18:04:05.769804"]]
(1.1ms) COMMIT
Redirected to http://localhost:3000/yazilar/23-post_title
Completed 302 Found in 29ms (ActiveRecord: 20.0ms)
Started GET "/yazilar/23-post_title" for ::1 at 2014-12-30 20:04:05 +0200
Processing by PostsController#show as HTML
Parameters: {"id"=>"23-post_title"}
Post Load (0.3ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = $1 LIMIT 1 [["id", 23]]
Rendered posts/show.html.erb within layouts/application (1.2ms)
Completed 200 OK in 191ms (Views: 186.1ms | ActiveRecord: 0.3ms)
Started GET "/yazilar/23-post_title/edit" for ::1 at 2014-12-30 20:04:15 +0200
Processing by PostsController#edit as HTML
Parameters: {"id"=>"23-post_title"}
Post Load (0.3ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = $1 LIMIT 1 [["id", 23]]
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
Rendered posts/_form.html.erb (5.1ms)
Rendered posts/edit.html.erb within layouts/application (8.1ms)
Completed 200 OK in 190ms (Views: 186.9ms | ActiveRecord: 0.5ms)
Started POST "/yazilar" for ::1 at 2014-12-30 20:04:23 +0200
Processing by PostsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"qy4qSDrdpqJa1SD4oGgXrGRqFway3PajR8PNQpOJEWO8kk18KqFq5cUQRXbm7HSfn00uk7lxgW63h4ahUbHv5w==", "post"=>{"title"=>"Post_title *update", "body"=>"<p>Post_body</p>", "postdate(1i)"=>"2014", "postdate(2i)"=>"12", "postdate(3i)"=>"30"}, "commit"=>"Save Post"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
(0.2ms) BEGIN
SQL (0.2ms) INSERT INTO "posts" ("title", "body", "postdate", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["title", "Post_title *update"], ["body", "<p>Post_body</p>"], ["postdate", "2014-12-30 00:00:00.000000"], ["created_at", "2014-12-30 18:04:23.969118"], ["updated_at", "2014-12-30 18:04:23.969118"]]
(6.0ms) COMMIT
Redirected to http://localhost:3000/yazilar/24-post_title-update
Completed 302 Found in 13ms (ActiveRecord: 6.7ms)
Started GET "/yazilar/24-post_title-update" for ::1 at 2014-12-30 20:04:23 +0200
Processing by PostsController#show as HTML
Parameters: {"id"=>"24-post_title-update"}
Post Load (0.3ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = $1 LIMIT 1 [["id", 24]]
Rendered posts/show.html.erb within layouts/application (0.8ms)
Completed 200 OK in 186ms (Views: 183.8ms | ActiveRecord: 0.3ms)
This is the _form partial
<%= form_for :post, url: posts_path do |post| %>
<% if #post.errors.any? %>
<h2><%= pluralize(#post.errors.count, "error") %> prevented this post from saving</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
<%= post.label :title %><br>
<%= post.text_field :title %><br>
<br>
<%= post.label :body %><br>
<%= post.text_area :body, :class => "redactor", :rows => 40, :cols => 40 %><br>
<br>
<%= post.label :postdate %><br>
<%= post.date_select :postdate %><br>
<br>
<%= post.submit %>

Your form_for is always pointing to create route, you can check your routes running rake routes in you app root.
Instead, replace first line in _form partial:
<%= form_for :post, url: posts_path do |post| %>
to:
<%= form_for #post do |post| %>
Now, the Rails will recognize if #post is a new record, or persisted record and write HTML form with the appropriate action (create or update respectively)

Related

App rolling back transactions and I don't know why

I am curious as to why my Rails app is rolling back transactions to DB without it being asked to.
Puma log:
Started POST "/posts" for 127.0.0.1 at 2019-01-05 00:32:32 -0500
Processing by PostsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"1AlwhyE0VY87oSyCyjmrzgxinJ7+t1TfoYYEDXvfl0pGd4DKE842KXHroFWgtXeusOgt+ZApHmB+e40qliTPjQ==", "post"=>{"title"=>"test", "category_id"=>"4", "body"=>"test"}, "commit"=>"Create Post"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 12], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:7
(0.2ms) begin transaction
↳ app/controllers/posts_controller.rb:14
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = ? LIMIT ? [["id", 4], ["LIMIT", 1]]
↳ app/controllers/posts_controller.rb:14
(0.1ms) rollback transaction
↳ app/controllers/posts_controller.rb:14
Redirected to http://localhost:3000/posts
Completed 302 Found in 18ms (ActiveRecord: 0.8ms)
Post controller:
class PostsController < ApplicationController
before_action :require_user
def index
#posts = Post.all
end
def new
#post = Post.new
#categories = Category.all
end
def create
#post = Post.new(post_params)
if #post.save(post_params)
#post.author = current_user.username
flash[:success] = "Post created."
redirect_to post_path(#post.id)
else
flash[:danger] = "Post not created. Redirecting to main page....."
redirect_to posts_path
end
end
View:
<%= form_for #post do |f| %>
<%= f.label :title, "Title of Post" %>
<%= f.text_field :title, class: "form-control" %>
<%= f.label :body, "Post Text" %>
<%= f.text_area :body, class: "form-control" %>
<%= f.submit "Create Post", class: "btn btn-info"%>
<% end %>
You're likely to have validation of the presence of the author field. Since it's set incorrectly in the create method, you have the transaction rolled back:
class PostsController < ApplicationController
...
def create
#post = Post.new(post_params)
if #post.save(post_params)
#post.author = current_user.username
flash[:success] = "Post created."
redirect_to post_path(#post.id)
...
end
In order to have author assigned and saved in the db, you need to assign the author before the saving:
class PostsController < ApplicationController
...
def create
#post = Post.new(post_params)
#post.author = current_user.username
if #post.save(post_params)
flash[:success] = "Post created."
redirect_to post_path(#post.id)
...
end
Depending on the version of Rails you have, and if you are using Strong Parameters, you must whitelist your parameters in the controller.
Example from docs:
private
# Using a private method to encapsulate the permissible parameters
# is just a good pattern since you'll be able to reuse the same
# permit list between create and update. Also, you can specialize
# this method with per-user checking of permissible attributes.
def person_params
params.require(:person).permit(:name, :age)
end

rails-4 devise + user controller edit route redirecting to the wrong place

I am using devise gem in my app and a custom user controller. I have links to edit a user in both the show and index page. After signing in, if I click the edit link in users/index.html.erb or users/edit.html.erb, it redirects to user new form even though a GET request was sent.
In the route, I am skipping registrable because I am using the User controller to handle that and it works fine.
this is the route
devise_for :users, :path_prefix => 'd', skip: [:registrations], controllers: {sessons: "sessions"}
resources :users
rake routes | grep edit_user gives
edit_user_password GET /d/users/password/edit(.:format) devise/passwords#edit
edit_user GET /users/:id/edit(.:format) users#edit
users/show.html.erb
<div class="btn btn-primary"> <%= link_to "Edit", edit_user_path(#user) %></div>
This is the screenshot of the registration form that comes up when I click on the edit link in either the index or show page. It is making a get request but displaying the form for new instead of form for edit.
The is the log from clicking the edit link in the show page:
Started GET "/users/17/edit" for at 2013-08-19 08:40:49 +0000
Processing by UsersController#edit as HTML
Parameters: {"id"=>"17"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", "17"]]
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 17 ORDER BY "users"."id" ASC LIMIT 1
Rendered users/_form.html.erb (17.5ms)
Rendered users/edit.html.erb within layouts/application (26.8ms)
Completed 200 OK in 50ms (Views: 47.1ms | ActiveRecord: 0.5ms
The users_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!, except: [:new, :create]
respond_to :html, :json
def show
end
def edit
end
private
def set_user
#user = User.find(params[:id])
end
end
users/_edit.html.erb I even specified url path in the form and it still renders new form
form_for(#user, :url => edit_user_path(#user))
users/edit.html.erb
<%= render "edit" %>
users/index.html.erb
<% #users.each do |user| %>
<div class="btn btn-primary"><%= link_to "Edit", edit_user_path(user) %> </div>
<div class="btn btn-danger"><%= link_to 'Remove', user, method: :delete, data: {confirmation: 'Are you sure'} %></div>
<% end %>
You are making a POST request to the edit user path whereas this path is registered with the GET method. That's why you get this error.
Personally, instead of skipping the registration, I would have overwritten the registrations controller as described in the Devise wiki.

Invalid Form Entry Causes Authlogic to Rollback to a Different Form

(Using Rails 3) I have authlogic set up to manage my users and user sessions (with a user controller and user_sessions controller and associated views, models, etc). I have two levels of user: an admin and a client. The admin can create users and edit users, and users are only able to look at documents on the website (no user editing or viewing privileges at all).
Then I implemented another controller (reset_password) which allows clients to change their password on the website. To do this I allowed clients to edit clients (so they can edit themselves). But The form that allows clients to change their password is much more limited than the form that allows admins to make clients.
The problem I am having is that when a client goes to the password editing form, and enters an invalid password or password confirmation, the page refreshes to the full admin form that lets clients change their privileges, etc. What I need is a way to force a failed form entry to return the client to the same form that they were just on rather than the admin form.
The problem, I am pretty sure, is because both the admin form and the client form use 'form_for #user do |f|' to define the form. I believe that rails cannot tell the two apart.
Here are the relevant files:
My admin form (users#edit with rendered form):
= stylesheet_link_tag :universal
= form_for #user do |f|
- if #user.errors.any?
#error_explanation
%span.boldHeader= "#{pluralize(#user.errors.count, "error")} prohibited this user from being saved:"
%ul
- #user.errors.full_messages.each do |msg|
%li= msg
.fieldContainer
.field
= f.label :username
= f.text_field :username
.field
= f.label :role
= f.collection_select :role, User::ROLES, :to_s, :humanize, { :selected => :client }
.fieldContainer
.field
= f.label :password
= f.password_field :password
.field
= f.label :password_confirmation
= f.password_field :password_confirmation
.fieldContainer
.field
= f.label :first_name
= f.text_field :first_name
.field
= f.label :last_name
= f.text_field :last_name
.field
= f.label :firm_name
= f.text_field :firm_name
.fieldContainer
.field
= f.label :email
= f.text_field :email
.field
= f.label :phone
= f.text_field :phone
.actions
= f.submit 'Save'
%a.button{ :href => "/users" }Cancel
My client form (reset_password#edit with rendered form):
= stylesheet_link_tag :universal
= form_for #user do |f|
- if #user.errors.any?
#error_explanation
%span.boldHeader= "#{pluralize(#user.errors.count, "error")} prohibited this user from being saved:"
%ul
- #user.errors.full_messages.each do |msg|
%li= msg
.fieldContainer
.field
= f.label :password
= f.password_field :password
.field
= f.label :password_confirmation
= f.password_field :password_confirmation
.actions
= f.submit 'Save'
%a.button{ :href => "/users" }Cancel
Client form update method:
def update
#user = current_user
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'Password successfully changed.' }
format.json { head :no_content }
else
format.json { render json: #user.errors, status: :unprocessable_entity }
format.html { redirect_to "/settings" }
end
end
Admin form update method:
def update
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'User was successfully updated' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
Note: /settings routes to reset_passwords#edit which has a partial render in it which is how I display the client form (see above). I also have users, user_sessions, and reset_passwords as resources in my routes file.
Finally, here is what I am seeing in the production log. You can see that I start in reset_password/_form (the client form) but then I get rolled back to users/_form (the admin form).
Started GET "/settings" for 127.0.0.1 at 2013-07-02 16:26:52 -0400
Processing by ResetPasswordsController#edit as HTML
User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Rendered reset_passwords/_form.html.haml (4.0ms)
Rendered reset_passwords/edit.html.haml within layouts/application (14.0ms)
Rendered shared/_header.html.haml (1.0ms)
Completed 200 OK in 57ms (Views: 54.0ms | ActiveRecord: 0.0ms)
[2013-07-02 16:26:52] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
Started GET "/assets/global.css?body=1" for 127.0.0.1 at 2013-07-02 16:26:52 -0400
Served asset /global.css - 304 Not Modified (0ms)
[2013-07-02 16:26:53] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
Started PUT "/users/1" for 127.0.0.1 at 2013-07-02 16:26:58 -0400
Processing by UsersController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"9KeHrOySL3FRhSnfYtVvKl2rCz9EPBSyGmtGGasDxnA=", "user"=>{"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Save", "id"=>"1"}
User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", "1"]]
User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
(0.0ms) begin transaction
User Exists (0.0ms) SELECT 1 AS one FROM "users" WHERE ("users"."persistence_token" = '5d1007bf94b34a7de44707e4ca432b18338f1c9ef6c5f99bf04845096a6b880057b5b43c917b9d38f790521ef62147eec3d9302471da73967048b48b4a399b18' AND "users"."id" != 1) LIMIT 1
(1.0ms) rollback transaction
Rendered users/_form.html.haml (9.0ms)
Rendered users/edit.html.haml within layouts/application (19.0ms)
Rendered shared/_header.html.haml (0.0ms)
Completed 200 OK in 80ms (Views: 61.0ms | ActiveRecord: 1.0ms)
I needed to specify the route for the form to take. Previously I had this in my "client" form (reset_password#edit with rendered form):
= form_for #user do |f|
I changed this to the following:
= form_for #user, :url => reset_password_path(#user) do |f|
I then also made some changes to the controller for the form:
def update
#user = current_user
#user.password = params[:user][:password]
#user.password_confirmation = params[:user][:password_confirmation]
respond_to do |format|
if !#user.changed?
format.html { redirect_to "/settings", notice: 'Form incomplete' }
format.json { render json: #user.errors, status: :unprocessable_entity }
elsif #user.save
format.html { redirect_to "/index", notice: 'Password successfully changed' }
format.json { head :no_content }
else
format.html { redirect_to "/settings", notice: 'Form incomplete' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
The part that I needed was the respond_to do |format|, the rest are just some logic changes to make it work better for my application.

"stack level too deep" error in show#controller for nested forms

I get an
SystemStackError in Admin::ChecklistsController#show
stack level too deep
The Controller Action:
# GET /admin/checklists/1
# GET /admin/checklists/1.json
def show
#admin_checklist = Admin::Checklist.find(params[:id])
respond_to do |format|
format.html #show.html.erb
format.json { render json: #admin_checklist }
end
end
And the models
class Admin::Checklist < ActiveRecord::Base
attr_accessible :description, :name, :usable, :categories_attributes
has_many :categories, :dependent => :destroy
validates_presence_of :name,:description
accepts_nested_attributes_for :categories, :allow_destroy => true
end
class Admin::Category < ActiveRecord::Base
attr_accessible :export_head, :export_position, :export_text, :frontend_head, :frontend_position, :frontend_text
belongs_to :checklist
validates_presence_of :frontend_head, :frontend_text
end
I already played around a bit with the attributes_accessible. If I replace :categories_attributes by :categories
Then I loose the endless loop error, but as expected, I can't mass-assign any category attributes anymore
Anyone got an idea how i can fix both errors.
EDIT:
Started GET "/admin/checklists/4" for 192.168.4.191 at 2012-12-12
10:12:41 +0100 Processing by Admin::ChecklistsController#show as HTML
Parameters: {"id"=>"4"} Admin::Checklist Load (0.2ms) SELECT
"admin_checklists".* FROM "admin_checkli
sts" WHERE "admin_checklists"."id" = ? LIMIT 1 [["id", "4"]] CACHE
(0.0ms) SELECT "admin_checklists".* FROM "admin_checklists" WHERE
"admi
n_checklists"."id" = ? LIMIT 1 [["id", "4"]] Completed 500 Internal
Server Error in 240ms
SystemStackError (stack level too deep): actionpack (3.2.9)
lib/action_dispatch/middleware/reloader.rb:70
Rendered
/var/lib/gems/1.9.1/gems/actionpack-3.2.9/lib/action_dispatch/middlew
are/templates/rescues/_trace.erb (1.5ms) Rendered
/var/lib/gems/1.9.1/gems/actionpack-3.2.9/lib/action_dispatch/middlew
are/templates/rescues/_request_and_response.erb (1.3ms) Rendered
/var/lib/gems/1.9.1/gems/actionpack-3.2.9/lib/action_dispatch/middlew
are/templates/rescues/diagnostics.erb within rescues/layout (10.7ms)
I get this SQL-Staement about 100 times for each Page request. This seems to be some bug in active record or miss-usage by me of active record for nested models .....
Edit2:
irb(main):001:0> Admin::Checklist.find('4') Admin::Checklist Load
(0.2ms) SELECT "admin_checklists".* FROM "admin_checkli
sts" WHERE "admin_checklists"."id" = ? LIMIT 1 [["id", "4"]]
=> #
BrummliBrummliBrummliBrummliBrummliBrummliBr...", usable: false,
created_at: "20 12-12-11 13:43:23",
updated_at: "2012-12-11 13:43:23">
Funny fact it now works and I'm not quite sure what really fixed it, because i changed nothing. I just came back from my break. Did the find on the console. Checked it in the template again and i got a different error message belonging to a malformed loop, because i had removed it again, which i fixed by pasting the removed part in again.
<p id="notice"><%= notice %></p>
<p>
<b>Name:</b>
<%= #admin_checklist.name %>
</p>
<p>
<b>Description:</b>
<%= #admin_checklist.description %>
</p>
<p>
<b>Usable:</b>
<%= #admin_checklist.usable %>
</p>
<p>
<ul>
<% #admin_checklist.categories.each do |category|%>
<li>
<h3><%= category.frontend_head %></h3>
<p><%= category.frontend_text %></p>
</li>
<% end %>
</ul>
</p>
<%= link_to 'Edit', edit_admin_checklist_path(#admin_checklist) %> |
<%= link_to 'Back', admin_checklists_path %>
I'm sorry I can't provide an answer why this happened.

update action not saving data

I am having trouble getting a form text area to update a field in a rails 3.0.8 app. I keep stripping out as much as i can to narrow down where the error lies. Here's what is left.
My form:
<%= form_for #fb_comments, :remote => true, :html => { :'data-type' => 'html', :id => 'comment' } do |form| %>
<%= form.text_area :comment %>
<%= form.submit "Update Comments" %>
<% end %>
The dummy data that i put into the comment column via mysql for this record shows up so the current data is making it to the form.
controller:
def update
fbc = FbComments.find(params[:id])
fbc.update_attributes(params[:comment])
...
end
console message:
Started POST "/fb_comments/1" for 127.0.0.1 at 2011-06-13 17:31:43 -0400
Processing by FbCommentsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"gLA2A11uVRl/WtIR1p90aSkLoU6b8twotK+B1YNefRk=", "fb_comments"=>{"comment"=>"test test"}, "commit"=>"Update Comments", "id"=>"1"}
FbComments Load (0.1ms) SELECT `fb_comments`.* FROM `fb_comments` WHERE `fb_comments`.`id` = 1 LIMIT 1
SQL (0.1ms) BEGIN
SQL (0.1ms) COMMIT
Rendered text template (0.0ms)
Completed 200 OK in 15ms (Views: 0.6ms | ActiveRecord: 0.3ms)
Thanks.
Your controller is recieving fb_comments not comment:
fbc.update_attributes(params[:fb_comments])
Hoe this helps.