Sadly loses my form after unsuccessful validation the data which have the user typed in. How can I change this, so that the form doesn't losing the data?
View _form.html.erb:
<%= form_for(#user, :html => {:name => "newUser""}) do |f| %>
<div class="field_left">
<%= f.label :last_name, "Last name<span>*</span>".html_safe %><br />
<%= f.text_field :last_name %>
</div>
<% end %>
<div class="field">
<%= f.fields_for :table1 do |ff| %>
<%= ff.text_field :name %>
<% end %>
</div>
Controller users_controller:
def new
#user = User.new
1.times {#user.table1.build}
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #user }
end
end
def create
#user = User.new(params[:user])
#table1= params[:user][:table1][:name]
respond_to do |format|
if #user.save
format.html { redirect_to(#user, :notice => 'User was successfully created.') }
format.xml { render :xml => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
Thanks for your help!
The solution is to set an instance variable as value like the following code.
<%= f.fields_for :table1 do |ff| %>
<%= ff.hidden_field :name, :value => #value %>
<% end %>
Use: <%= f.fields_for #table1 do |ff| %>
Make sure that #table1 is set in the controller with the data that is received from the form submission.
Is better to use
<%= f.fields_for :table1, f.object.table1 do |ff| %>
<% ff.text_field :name %>
<% end %>
You won't have to set values, i.e. <% ff.text_field :name, value: 'something' %>.
Related
I am new to Rails and was creating a demo web shop app for study.
I could create the products smoothly, both via rails console and by the url localhost:300/products/new.
My problem is when I want to update them.
I have _form.html.erb partial getting rendered both in new.html.erb and edit.html.erb
In /products/id/edit though the button "Update Product" is actually destroying the product instead of updating it
This is the _form.htlm.erb:
<%= form_for(#product) do |f| %>
<% if #product.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% #product.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="row">
<div class="col-sm-4 col-xs-12">
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name, :class => "input-group input-group-sm" %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :image_url %><br>
<%= f.text_field :image_url %>
</div>
<div class="field">
<%= f.label :color %><br>
<%= f.text_field :color %>
</div>
<div class="actions">
<%= f.submit %>
</div>
</div>
</div>
Please tell me if you need more data
Thanks,
Anna
Updat: here below my routes.rb
Rails.application.routes.draw do
resources :products
get 'news/index' => 'news#index', as: :news
get 'store' => 'store#index', as: :store
get 'contact' => 'contact#index', as: :contact
get 'products/edit' => 'products#edit'
get 'products/destroy' => 'products#destroy'
get 'about' => 'about#index', as: :about
get 'landing_page' => 'static_pages#landing_page', as: :landing_page
get 'home/index'
root 'static_pages#landing_page'
resources :orders, only: [:index, :show, :create, :destroy]
I have pryed in the products_controller and found this:
# GET /products/1
# GET /products/1.json
def show
end
# GET /products/new
def new
#product = Product.new
end
# GET /products/1/edit
def edit
end
# POST /products
# POST /products.json
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /products/1
# PATCH/PUT /products/1.json
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: #product }
else
format.html { render :edit }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# DELETE /products/1
# DELETE /products/1.json
def destroy
#product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
format.json { head :no_content }
end
end
The Edit.html.erb had also three options for: Show|Delete|Back The Delete option was coded with : <%= link_to 'Delete', #product.destroy %> I deleted this line and the product got edited instead of being cancelled.
I have spent a while trying and searching for answers to debug this.
I am following Railscast 250 (Authentication from scratch) which is intended for Rails 3 on Rails 4.
Obviously there is a problem of strong parameters which I think I have solved using the usual method.
I am currently getting this error:
undefined method `password' for #User:0xb640d880
Extracted source (around line #32):
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render action: 'show', status: :created, location: #user }
else
I know the controller can access the password attribute, but for some reason the model can't even though I am validating the presence of :password in the model.
user.rb
class User < ActiveRecord::Base
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates_presence_of :email
validates_uniqueness_of :email
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
users_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
#users = User.all
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
logger.warn user_params[:password]
#user = User.new(email: user_params[:email], password_hash: user_params[:password_hash], password_salt: user_params[:password_salt])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render action: 'show', status: :created, location: #user }
else
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
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
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:email, :password_hash, :password_salt, :password)
end
end
_form.html.erb (view)
<%= form_for(#user) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :email %><br>
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :password %><br>
<%= f.password_field :password %>
</div>
<div class="field">
<%= f.label :password %><br>
<%= f.password_field :password %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Thanks for your help!
I have created an sample project of user authentication so please check it.
Users_controller.rb
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
#raise params.inspect
if #user.save
redirect_to root_url, :notice => "Signed up!"
else
render "new"
end
end
private
def user_params
params.require(:user).permit(:email, :password_hash, :password_salt, :password)
end
end
new.html.erb
<h1>Sign Up</h1>
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2>Form is invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :email %><br />
<%= f.text_field :email %>
</p>
<p>
<%= f.label :password %><br />
<%= f.password_field :password %>
</p>
<p>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
</p>
<p class="button"><%= f.submit %></p>
<% end %>
user.rb
class User < ActiveRecord::Base
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
#validates_presence_of :password, :on => :create
validates_presence_of :email
validates_uniqueness_of :email
def encrypt_password
#raise password.inspect
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
Above code is working properly.
Your model is missing an attr_accessor for password. As you don't have a password column in your table but still need to receive the password attribute (so you can process it with a salt and then turn it into a hash), you need to have this accessor.
Add this in your user model:
attr_accessor :password
EDIT: Just like Amit Sharma pointed out in his demo.
ActiveRecord::RecordNotFound in UsersController#index
Couldn't find UserSession without an ID
Rails.root: C:/Sites/login_app
Application Trace | Framework Trace | Full Trace
app/controllers/application_controller.rb:9:in current_user_session'
app/controllers/application_controller.rb:14:incurrent_user'
app/views/layouts/application.html.erb:12:in _app_views_layouts_application_html_erb__233847886_33215772'
app/controllers/users_controller.rb:7:inindex'
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :current_user private
def current_user_session
return #current_user_session if defined?(#current_user_session)
#current_user_session = UserSession.find
end
def current_user
return #current_user if defined?(#current_user)
#current_user = current_user_session && current_user_session.record
end
end
class HomeController < ApplicationController
def index
end
end
class UserSessionsController < ApplicationController
def new
#user_session = UserSession.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #user_session }
end
end
def create
#user_session = UserSession.new(params[:user_session])
respond_to do |format|
if #user_session.save
format.html { redirect_to(:users, :notice => 'Login Successful') }
format.xml { render :xml => #user_session, :status => :created, :location => #user_session }
else
format.html { render :action => "new" }
format.xml { render :xml => #user_session.errors, :status => :unprocessable_entity }
end
end
end
def destroy
#user_session = UserSession.find
#user_session.destroy
respond_to do |format|
format.html { redirect_to(:users, :notice => 'Goodbye!') }
format.xml { head :ok }
end
end
end
class UsersController < ApplicationController
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
def edit
#user = User.find(params[:id])
end
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to(:users, :notice => 'Registration successfull.') }
format.xml { render :xml => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
def update
#user = User.find(params[:id])
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
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end
layout/apllication.html
LoginApp
<%= stylesheet_link_tag :all %>
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>
<% if current_user %>
<%= link_to "Edit Profile", edit_user_path(current_user.id)%>
<%= link_to "Logout", :logout%>
<% else %>
<%= link_to "Register", new_user_path%>
<%= link_to "Login", :login %>
<% end %>
<%= yield %>
user_seesion/_form.html
<%= form_for(#user_session) do |f| %>
<% if #user_session.errors.any? %>
<%= pluralize(#user_session.errors.count, "error") %> prohibited this user_session from being saved:
<% #user_session.errors.full_messages.each do |msg| %>
<%= msg %>
<% end %>
<% end %>
<%= f.label :username %>
<%= f.text_field :username %>
<%= f.label :password %>
<%= f.password_fields :password %>
<%= f.submit %>
<% end %>
user_sessions/edit.html
Editing user_session
<%= render 'form' %>
<%= link_to 'Show', #user_session %> |
<%= link_to 'Back', user_sessions_path %>
user_sessions/index.html :
Listing user_sessions
Username
Password
<% #user_sessions.each do |user_session| %>
<%= user_session.username %>
<%= user_session.password %>
<%= link_to 'Show', user_session %>
<%= link_to 'Edit', edit_user_session_path(user_session) %>
<%= link_to 'Destroy', user_session, method: :delete, data: { confirm: 'Are you sure?' } %>
<% end %>
<%= link_to 'New User session', new_user_session_path %>
user_sessions/new.html
Login
<%= render 'form' %>
<%= link_to 'Back', user_sessions_path %>
user_sessions/show.html
<%= notice %>
Username:
<%= #user_session.username %>
Password:
<%= #user_session.password %>
<%= link_to 'Edit', edit_user_session_path(#user_session) %> |
<%= link_to 'Back', user_sessions_path %>
-users/_form.html
<%= form_for(#user) do |f| %>
<% if #user.errors.any? %>
<%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:
<ul><br/>
<% #user.errors.full_messages.each do |msg| %><br/>
<li><%= msg %></li><br/>
<% end %><br/>
</ul><br/>
</div><br/>
<% end %>
<%= f.label :username %>
<%= f.text_field :username %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
<%= f.submit 'create user'%>
<% end %>
users/edit.html
Editing user
<%= render 'form' %>
<%= link_to 'Show', #user %> |
<%= link_to 'Back', users_path %>
users/index.html :
Listing users
<%= notice %>
Username
Email
<% #users.each do |user| %>
<%= user.username %>
<%= user.email %>
<%= link_to 'Show', user %>
<%= link_to 'Edit', edit_user_path(user) %>
<%= link_to 'Destroy', user, :confirm => 'Are you sure?', :method => :delete %>
<% end %>
<%= link_to 'New User', new_user_path %>
users/new.html :
New user
<%= render 'form' %>
<%= link_to 'Back', users_path %>
users/show.html :
<%= notice %>
Username:
<%= #user.username %>
Email:
<%= #user.email %>
Crypted password:
<%= #user.crypted_password %>
Password salt:
<%= #user.password_salt %>
Persistence token:
<%= #user.persistence_token %>
<%= link_to 'Edit', edit_user_path(#user) %> |
<%= link_to 'Back', users_path %>
In user_session.rb, you need to change the inherited class to Authlogic::Session::Base, like so:
class UserSession < Authlogic::Session::Base
...
end
Also, next time use a gist or something similar to paste large chunks of code, or format it at least. Hope that helps!
Basically whats happening is I can create a new item that gets saved to my table in my db. but when I go to edit the item, the form opens up, I make the change and then when I go to submit, it takes me to the same url as the edit page and gives me Routing Error No route matches "/support/14/edit" although if you enter that in the address bar it opens the edit form just fine, but doesn't have any of my changes saved. So here is my code.
routes.rb
resources :support
support_controller.rb
def new
#support_item = Support.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #support_item }
end
end
# GET /support/1/edit
def edit
#support_item = Support.find(params[:id])
end
# POST /support
# POST /support.xml
def create
#support_item = Support.new(params[:support_item])
respond_to do |format|
if #support_item.save
format.html { redirect_to("/support", :notice => 'Question was successfully created.') }
else
format.html { render :action => "new" }
end
end
end
# PUT /support/1
# PUT /support/1.xml
def update
#support_item = Support.find(params[:id])
respond_to do |format|
if #support_item.update_attributes(params[:support_item])
format.html { redirect_to("/", :notice => 'Question was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #support_item.errors, :status => :unprocessable_entity }
end
end
end
support.rb
class Support < ActiveRecord::Base
belongs_to :role
scope :admin_available, order("role_id ASC") do
Support.all
end
def self.available(user)
questions = where(:role_id => 1)
questions += where(:role_id => user.roles)
questions
end
end
_form.html.erb
<% if #support_item.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#support_item.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul>
<% #support_item.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label "Support item for:" %><br />
<%= f.collection_select :role_id, Role.find_by_max(5), :id, :name, {:default => 'everyone'} %>
</div>
<div class="field">
<%= f.label :question %><br />
<%= f.text_field :question, :class => 'genForm_question'%>
</div>
<div class="field">
<%= f.label :answer %><br />
<%= f.text_area :answer, :class => 'genForm_textarea' %>
</div>
<div class="field">
<%= f.label :url %><br />
<%= f.text_field :url, :class => 'genForm_question' %>
</div>
<div class="actions">
<%= f.submit %>
</div>
new.html.erb
<h1>New Support Item</h1>
<% form_for #support_item, :url => { :action => "create" }, :html => { :method => :post } do |f| %>
<%= render 'form', :f => f %>
<% end %>
edit.html.erb
<h1>Editing Support Item</h1>
<% form_for #support_item, :url => { :action => "edit" }, :html => { :method => :post } do |f| %>
<%= render 'form', :f => f %>
<% end %>
I believe thats all the relavent code.
<h1>Editing Support Item</h1>
<% form_for #support_item do |f| %>
<%= render 'form', :f => f %>
<% end %>
You are overriding the URL. It should be able to be auto-generated like that if you are doing everything with standard rest. If that doesn't work out, just know you don't want to submit to /support_items/1/edit, you want to submit to /support_items/1.
So I ran a regular generate scaffold and used a stock form to handle uploads.
All uploads work nicely and the image is attached perfectly. The issue I get is when I go to 'Edit' and try to change the image, this is the error I get:
Routing Error
No route matches "/uploads"
Here is what my controller looks like. The name is 'uploads_controller.rb'
class UploadsController < ApplicationController
# GET /uploads
# GET /uploads.xml
def index
#uploads = Upload.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #uploads }
end
end
# GET /uploads/1
# GET /uploads/1.xml
def show
#upload = Upload.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #upload }
end
end
# GET /uploads/new
# GET /uploads/new.xml
def new
#upload = Upload.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #upload }
end
end
# GET /uploads/1/edit
def edit
#upload = Upload.find(params[:id])
end
# POST /uploads
# POST /uploads.xml
def create
#upload = Upload.new(params[:upload])
respond_to do |format|
if #upload.save
format.html { redirect_to(#upload, :notice => 'Upload was successfully created.') }
format.xml { render :xml => #upload, :status => :created, :location => #upload }
else
format.html { render :action => "new" }
format.xml { render :xml => #upload.errors, :status => :unprocessable_entity }
end
end
end
# PUT /uploads/1
# PUT /uploads/1.xml
def update
#upload = Upload.find(params[:id])
respond_to do |format|
if #upload.update_attributes(params[:upload])
format.html { redirect_to(#upload, :notice => 'Upload was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #upload.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /uploads/1
# DELETE /uploads/1.xml
def destroy
#upload = Upload.find(params[:id])
#upload.destroy
respond_to do |format|
format.html { redirect_to(uploads_url) }
format.xml { head :ok }
end
end
end
The 'upload.rb' model file looks like this:
class Upload < ActiveRecord::Base
has_attached_file :image
end
show.html.erb
<p id="notice"><%= notice %></p>
<p>
<b>Name:</b>
<%= #upload.name %>
</p>
<p>
<b>Description:</b>
<%= #upload.description %>
</p>
<p>
<b>Your Image:</b>
<%= image_tag #upload.image.url %>
</p>
<%= link_to 'Edit', edit_upload_path(#upload) %> |
<%= link_to 'Back', uploads_path %>
edit.html.erb
<h1>Editing upload</h1>
<%= render 'form' %>
<%= link_to 'Show', #upload %> |
<%= link_to 'Back', uploads_path %>
_form.html.erb
<%= form_for (#upload), :url => uploads_path, :html => { :multipart => true } do |f| %>
<% if #upload.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#upload.errors.count, "error") %> prohibited this upload from being saved:</h2>
<ul>
<% #upload.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br />
<%= f.text_field :description %>
</div>
<div class="field">
<%= f.file_field :image %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Thanks.
Edit: Relevant part of the 'rake routes' output:
uploads GET /uploads(.:format) {:action=>"index", :controller=>"uploads"}
uploads POST /uploads(.:format) {:action=>"create", :controller=>"uploads"}
new_upload GET /uploads/new(.:format) {:action=>"new", :controller=>"uploads"}
edit_upload GET /uploads/:id/edit(.:format) {:action=>"edit", :controller=>"uploads"}
upload GET /uploads/:id(.:format) {:action=>"show", :controller=>"uploads"}
upload PUT /uploads/:id(.:format) {:action=>"update", :controller=>"uploads"}
upload DELETE /uploads/:id(.:format) {:action=>"destroy", :controller=>"uploads"}
So it seems the error was in my _form partial.
I had a :url attribute defined, when I shouldn't have.
Paperclip needs to update their install instructions to reflect that change for Rails 3.
The wonderful guys in #RubyOnRails on irc.freenode.net helped me out with this one.