Hello after creating a Product i can't edit it. The form a little complex so its made it i hard to get the edit to work.
Error when i try to edit.
Completed 500 Internal Server Error in 16ms
ActionView::Template::Error (undefined method `map' for nil:NilClass):
17:
18: <p><%= f.link_to_add "Add a image", :product_images, :data => { :product_image => "#product_images" } %></p>
19:
20: <%= f.collection_select :category_id, #categories, :id, :name, include_blank: true, prompt: "Select One Category" %>
21:
22: <% #categories.each do |category| %>
23: <div class='sizes_container' id
Here is the Product form.
<%= javascript_include_tag "custom" %>
<div class="container">
<div class=“row”>
<div class="col-md-6 col-md-offset-3">
<div class="panel panel-primary">
<div class="panel-body">
<%= simple_nested_form_for #product do |f| %>
<%= f.fields_for :product_images do |product_image| %>
<% if product_image.object.new_record? %>
<%= product_image.file_field(:product_image) %>
<%= product_image.link_to_remove "Remove Image", data: { confirm: "Are you sure you want to delete this image?" } %>
<% else %>
<%= product_image.hidden_field :_destroy %>
<% end %>
<% end %>
<p><%= f.link_to_add "Add a image", :product_images, :data => { :product_image => "#product_images" } %></p>
<%= f.collection_select :category_id, #categories, :id, :name, include_blank: true, prompt: "Select One Category" %>
<% #categories.each do |category| %>
<div class='sizes_container' id ='sizes_container_for_<%= category.id %>'>
<% category.sizes.each do |size| %>
<%= label_tag size.title %>
<%= f.simple_fields_for :product_sizes do |product_size| %>
<%= product_size.input :quantity %>
<%= product_size.hidden_field :size_id %>
<% end %>
<% end %>
</div>
<% end %>
<%= f.input :title, label:"Title"%>
<%= f.input :price, label:"Price"%>
<%= f.input :description,label:"Description" %>
<%= f.input :size_description, label:"Size Details"%>
<%= f.input :shipping_description, label:"Shipping Details"%>
<%= f.input :tag_list,label:"Tags - Seperate tags using comma ','. 5 tags allowed per product" %>
<%= f.button :submit, "Create new product", class: "btn-lg btn-success" %>
<% end %>
</div>
</div>
</div>
</div>
</div>
Any ideas? I had a look around the net i couldn't find the answer. So any help would be great. Thank you in advance.
Products controller
class ProductsController < ApplicationController
before_action :set_product, only: [:edit, :show, :update]
before_action :correct_user_edit, only: [:edit, :update, :destroy]
before_action :logged_in_user, only: [:new, :edit, :update, :destroy]
def index
#products = Product.all
end
def new
#product = Product.new
#categories = Category.preload(:sizes).order(:name)
#product.product_images.build
#product.product_sizes.build
end
def home
#products = Product.paginate(page: params[:page])
end
def edit
end
def show
end
def update
if #product.update(product_params)
redirect_to #product
flash[:success] = 'Item was successfully updated.'
else
render "edit"
end
end
def create
#product = Product.new product_params
#product.user_id = current_user.id
if #product.save
redirect_to #product
flash[:success] = "You have created a new product"
else
flash[:danger] = "Your product didn't save"
render "new"
end
end
def destroy
#product.destroy
flash[:success] = "Product deleted"
redirect_to user_products_path
end
def add_outfit_products
#products = current_user.products
end
def add_outfit_similar_products
#products = current_user.products
end
private
def create_product_images
params["product"]["product_images_attributes"].each do |index, image|
ProductImage.create(product_image: image, product_id: #form.product.id)
end
end
def set_product
#product = Product.find(params[:id])
end
def product_params
params.require(:product).permit(
:title,
:price,
:description,
:tag_list,
:category_id,
:size_description,
:shipping_description,
product_images_attributes: [:product_image, :_destroy],
product_sizes_attributes: [:size_id, :quantity]
)
end
def correct_user_edit
if #product = current_user.products.find_by(id: params[:id])
else
redirect_to root_url if #product.nil?
end
end
end
it seems like your #categories = nil, but should be #categories = [] array.
Check your Controller - Action edit, do you define #categories?
Related
Hey Guys I am getting issue, No Route Matches, though I have created both new as well as create method.
portfollios_controller.rb
class PortfolliosController < ApplicationController
def index
#portfolio_items = Portfollio.all
end
def new
#portfolio_item = Portfollio.new
end
def create
#portfolio_item = Portfollio.new(params.require(:portfollio).permit(:title, :subtitle, :body))
respond_to do |format|
if #portfolio_item.save
format.html { redirect_to portfollio_path, notice: 'Your portfolio item is now live.' }
else
format.html { render :new }
end
end
end
end
routes.rb
Rails.application.routes.draw do
resources :portfollios
end
new.html.erb
<h1>Create a new Portfolio Item</h1>
<%= form_with(model: #portfolio_items, local: true) do |form| %>
<div class="field">
<%= form.label :title %>
<%= form.text_field :title %>
</div>
<div class="field">
<%= form.label :subtitle %>
<%= form.text_field :subtitle %>
</div>
<div class="field">
<%= form.label :body %>
<%= form.text_area :body %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
Can someone help me out with the issue. I am not able to figure it out.
I figured it out. The issue is with with the file new.html.erb
I needed to change below line:-
<%= form_with(model: #portfolio_items, local: true) do |form| %>
to
<%= form_with(model: #portfolio_item, local: true) do |form| %>
It should be #portfolio_item not plural.
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!
I am trying to flash messages in a form when they do not meet the validation requirements but can't work out how to achieve this.
I have the following setup:
models/item.rb
class Item < ActiveRecord::Base
attr_accessible :condition, :day, :description, :subtitle, :title
validates :user_id, presence: true
validates :title, presence: true
validates :description, presence: true, length: { minimum: 20 }
belongs_to :user
end
controllers/items_controller.rb
class ItemsController < ApplicationController
before_filter :authenticate_user!
def new
#item = Item.new
end
def show
#item = Item.find(params[:id])
end
def create
#item = current_user.items.build(params[:item])
if #item.save
flash[:success] = "Your item has been saved"
redirect_to root_path
else
render 'new'
end
end
def destroy
#item.destroy
redirect_back_or root_path
end
end
and finally views/items/new.html.erb
<h1>Items Base</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#item) do |f| %>
<%= f.label :title, "Title" %>
<%= f.text_field :title %>
<%= f.label :subtitle, "Subtitle" %>
<%= f.text_field :subtitle %>
<%= f.label :condition, "Condition" %>
<%= f.number_field :condition %>
<%= f.label :description, "Description" %>
<%= f.text_field :description %>
<%= f.label :day, "Day" %>
<%= f.text_field :day %>
<%= f.submit "List", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
Essentially I would like to be able to flash the message "Description too short!" when the user leaves it blank or below 20 characters, or flash the message "Title required" if it is left blank. Any thoughts on how best to achieve this. Also if anyone has any good resources on working with the flash it would be much appreciated. Thanks.
Here is how I do it:
Here is the form:
<%= form_for(#client) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :company_name %>
<%= f.text_field :company_name %>
<%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>
And here is my error_messages partial:
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(object.errors.count, "error") %>.
</div>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
I give up. I'm trying to build a simple nested form with 2 models following Railscasts #196 episode and doesn't work. Can someone send a working example please so I can test on my environment. I'm using 3.1.0
For example when I try to build 3 questions on the form only 1 question field appears, then survey_id is never passed across.
I would appreciate your help after 2 days and nights on it. I got missing something really big. Thanks
Model
class Survey < ActiveRecord::Base
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions
attr_accessible :name, :questions_attributes
end
class Question < ActiveRecord::Base
belongs_to :survey
attr_accessible :survey_id, :name
end
Controller
def new
#survey = Survey.new
4.times { #survey.questions.build }
respond_to do |format|
format.html # new.html.erb
format.json { render json: #survey }
end
end
def create
#survey = Survey.new(params[:survey])
respond_to do |format|
if #survey.save
format.html { redirect_to #survey, notice: 'Survey was successfully created.' }
format.json { render json: #survey, status: :created, location: #survey }
else
format.html { render action: "new" }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
View
<%= form_for(#survey) do |f| %>
<% if #survey.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#survey.errors.count, "error") %> prohibited this survey from being saved:</h2>
<ul>
<% #survey.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>
<%= fields_for :questions do |builder| %>
<%= builder.label :name, "Question" %>
<%= builder.text_field :name %>
<% end %>
<br /><br />
<div class="actions">
<%= f.submit %>
</div>
<% end %>