Rails - Attribute is nil when using form_for helper method - ruby-on-rails

Brand new to rails here. I'm trying to implement a user authentication system using a password and a hashing algorithm. Now when I try to create a new user, the password attribute of the user is always nil.
Here is my User/new view:
<% #page_title = 'New Users' %>
<div class="user new">
<h2>Create User</h2>
<%= form_for(:user, :url => {:action => 'create'}) do |f| %>
<%= render(:partial => 'form', :locals => {:f => f} ) %>
<div class="form-buttons">
<%= submit_tag('Create User') %>
</div>
<% end %>
</div>
<%= link_to 'Back', users_path %>
And my partial layout _form:
<% 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 %>
<table summary="Admin user form fields">
<tr>
<th><%= f.label(:first_name) %></th>
<td><%= f.text_field(:first_name) %></td>
</tr>
<tr>
<th><%= f.label(:last_name) %></th>
<td><%= f.text_field(:last_name) %></td>
</tr>
<tr>
<th><%= f.label(:email) %></th>
<td><%= f.text_field(:email) %></td>
</tr>
<tr>
<th><%= f.label(:password) %></th>
<td><%= f.text_field(:password) %></td>
</tr>
</table>
However, by the time we get to the controller, #user.password is always nil. Why isn't the value of the :password form being brought through? Code from the controller:
def create
#user = User.new(user_params)
flash[:notice] = "Password: " + #user.password #ALWAYS NIL
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
Password is attr_accessor in the model. Here is the model code:
class User < ActiveRecord::Base
attr_accessor :password #not value in database, only in model
validates_length_of :password, :within => 6..25, :on => :create
before_save :create_hashed_password
after_save :clear_password
def self.hash_with_salt(password= "", salt="")
Digest::SHA1.hexdigest("Put #{salt} on the #{password}")
end
#makes a salt for encription using the user's email (unique) and time (random)
def self.make_salt(email="")
Digest::SHA1.hexdigest("Use #{email} with #{Time.now} 2 make salt")
end
#will return user if login is successful else returns fasle
def self.authenticate(email="", password="")
user = User.find_by_email(email)
if user && user.password_match?(password)
return user
else
return false
end
end
#The same password string with the same hash method should always generate
#the same hashed_password
def password_match?(password="")
hashed_password == User.hash_with_salt(password, salt)
end
private
def create_hashed_password
#Whenever :password has a value, hashing is needed
unless password.blank?
self.salt = User.make_salt(username) if salt.blank?
self.hashed_password = User.hash_with_salt(password, salt)
end
end
def clear_password
self.password = nil
end
end
Thanks in advance for your help.

In your create action change this:
#user = User.new(user_params)
to
#user = User.new(params[:user])

Related

How to edit data onclick button using rails gem 'best_in_place'?

I am using rails gem 'best_in_place' and data edit one by one, as clicked perticular field.
how can i active all fields for editable onclick update/edit button?
def update
if m_user[:name].present?
MUser.where(:id => id).update(:name => m_user[:name])
elsif m_user[:gender].present?
MUser.where(:id => id).update(:gender => m_user[:gender])
else
flash[:danger] = 'not updated'
end
end
View code:
<% #user.each do |record| %>
<tr>
<td>
<%= best_in_place record, :name, :as => :input %>
</td>
<td>
<%= best_in_place record, :gender, :as => :select, collection: (MUser.pluck(:id,:gender)) %>
</td>
<%= best_in_place record, :dob, :as => :date, class: 'datepicker1 %>
</td>
</tr>
<% end %>
<%= submit_tag('update',:name => 'update_data', class: 'btn btn-primary btn-sm', :id => 'update_btn') %>
Now data edit like if i edit name it will automatically editable
,but how can I edit when i clicked update/edit button then make all fields active for edit.
As we discussed, you need to do a couple of changes
Add a _user.html.erb partial to render the records with below code.
<td>
<%= user.name %>
</td>
<td>
<%= user.gender %>
</td>
<td>
<%= user.dob %>
</td>
<td>
<%= link_to "Edit", edit_user_path(user), remote: true %>
<td>
Now change your index.html.erb code like below.
<% #users.each do |user| %>
<tr id="record-row-<%= user.id %>">
<%= render prtial: 'user', locals: { user: user } %>
</tr>
<% end %>
Now refresh your page and you will see the User records in table rows.
Add a new partial _user_form.html.erb to render the form and add below code in it.
<td colspan="4">
<%= form_for(#user, remote: true) do |f|
<table>
<tbody>
<tr>
<td><%= f.text_field :name, class: 'form-control' %></td>
<td><%= f.select :gender, MUser.pluck(:gender, :id).uniq, { selected: #user.gender }, class: 'form-control' %></td>
<td><%= f.text_field :name, class: 'form-control datepicker1' %></td>
<td><%= f.submit "Update" %></td>
</tr>
</tbody>
</table>
<% end %>
</td>
Now need to update edit and update actions.
edit action
def edit
#user = User.find(params[:id])
respond_to do |format|
format.js { }
format.html { render 'edit' }
end
end
update action
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(user_params)
format.js { }
format.html { redirect_to #user, notice: 'User was updated successfully.' }
else
format.js { }
format.html { render 'edit' }
end
end
end
private
def user_params
params.require(:user).permit(:name, :gender, :dob)
end
Now you need to create an edit.js.erb file to render the form on selected row.
$("#record-row-<%= #user.id %>").html("<%= escape_javascript(render 'user_form') %>")
And you also need an update.js.erb file to update the table row after updating the user record.
$("#record-row-<%= #user.id %>").html("<%= escape_javascript(render partial: 'user', locals: { user: #user } ) %>")
Now all set. Refresh your page and click on Edit button of a row. A form will appear. Change the value and click on Update button. You will see the updated record.
Let me know if you have nay issues. Happy to help.

I get this error: "'3' is not an ActiveModel-compatible object. It must implement :to_partial_path." and it only happens when I add validations

This is the error I get.
This is my model code.
class Subject < ActiveRecord::Base
has_many :pages
validates :name,
:presence => true,
:length => { :maximum => 255 }
scope :visible, lambda { where(:visible => true) }
scope :invisible, lambda { where(:visible => false) }
scope :sorted, lambda { order("subjects.position ASC")}
scope :newest_first, lambda { order("subject.created_at DESC") }
scope :search, lambda { |query|
where(["name LIKE ?", "%#{query}%"])
}
end
I noticed that it's saying something about my create action. So here's that:
class SubjectsController < ApplicationController
layout "admin"
def index
#subjects = Subject.sorted
end
def show
#subject = Subject.find(params[:id])
end
def new
#subject = Subject.new({:name => 'Default'})
#subject_count = Subject.count + 1
end
def create
# Instantiate a new object using form parameters
#subject = Subject.new(subject_params)
# Save the object
if #subject.save
# If save succeeds, redirect to the index
flash[:notice] = "The subject was created successfully."
redirect_to(:action => 'index')
else
#subject_count = Subject.count + 1
render(new)
end
end
def edit
#subject = Subject.find(params[:id])
#subject_count = Subject.count
end
def update
# Find an existing object using form parameters
#subject = Subject.find(params[:id])
# Update the object
if #subject.update_attributes(subject_params)
# If save succeeds, redirect to the show
flash[:notice] = "The subject was updated successfully."
redirect_to(:action => 'show', :id => #subject.id)
else
# If update fails, redisplay the form so user can fix problem.
#subject_count = Subject.count
render('edit')
end
end
def delete
#subject = Subject.find(params[:id])
end
def destroy
subject = Subject.find(params[:id]).destroy
flash[:notice] = "The subject '#{subject.name}' was deleted successfully."
redirect_to(:action => 'index')
end
private
def subject_params
# same as using "params[:subject]", except that it:
# -raises an error if :subject is not present
# -allows listed attributes to be mass-assigned
params.require(:subject).permit(:name, :position, :visible)
end
end
If I take the validations off it works, but then I can create the subject without a name. I noticed that if I add a subject the number in the paranthesis '3' moves up. I wonder if it has something to do with the select form. Here's the form:
<%= error_messages_for(#subject) %>
<table summary="Subject form fields" class="table table-hover">
<tr>
<th><%= f.label(:name, "Name") %></th>
<td><%= f.text_field(:name) %></td>
</tr>
<tr>
<th><%= f.label(:position) %></th>
<td><%= f.select(:position, 1..#subject_count) %></td>
</tr>
<tr>
<th><%= f.label(:visible) %></th>
<td><%= f.check_box(:visible) %></td>
</tr>
</table>
Update: I'm adding the index view per request.
<% #page_title = 'Subjects' %>
<div class="subjects show">
<h2>Subjects</h2>
<%= link_to("Add New Subject", {:action => 'new'}, :class => 'action new btn btn-default') %>
<table class="listing table table-hover" summary="Subject list">
<tr class="header">
<th>Position</th>
<th>Subject</th>
<th>Visible</th>
<th>Pages</th>
<th>Actions</th>
</tr>
<% #subjects.each do |subject| %>
<tr>
<td><%= subject.position %></td>
<td><%= subject.name %></td>
<td class="center"><%= subject.visible ? 'Yes' : 'No' %></td>
<td class="center"><%= subject.pages.size %></td>
<td class="actions">
<%= link_to("Show", {:action => 'show', :id => subject.id}, :class => 'action show') %>
<%= link_to("Edit", {:action => 'edit', :id => subject.id}, :class => 'action edit') %>
<%= link_to("Delete", {:action => 'delete', :id => subject.id}, :class => 'action delete') %>
</td>
</tr>
<% end %>
</table>
</div>
due to a syntax error for the partial on the else part of create action, active model was throwing an exception(http://apidock.com/rails/v3.2.1/ActionView/PartialRenderer/partial_path)
def create
#few lines escaped....
else
#subject_count = Subject.count + 1
render(new) # <-- Error
end
It should be either render :new or render 'new' as mentioned by Nobilik. your method should look like:
def create
#few lines escaped....
else
#subject_count = Subject.count + 1
render :new # for best practice
end

ActiveSupport::HashWithIndifferentAccess

My contorller is like this
class FriendController < ApplicationController
def friend_list
#user = User.new
end
def be_mine_friend
#user = params[:user]
if #user.save?
redirect_to friend_mine_friend_url
flash[:notice] = "#{#user[:name]} have been added to my friend list"
else
redirect_to friend_friend_list_path
end
end
def mine_friend
#title = "Details list of Mine Friend"
#friend = #user.paginate(page: params[:page], per_page: 10)
respond_to do |format|
format.html
format.json { render json: #friend }
end
end
end
View page for friend_list
<div class="container">
<%= notice %>
<%#= errors %>
<%= form_for(#user, url: friend_be_mine_frien_path) do |user| %>
<%= user.text_field 'name', placeholder: "Your name Please" %></br>
<%= user.text_field 'email', placeholder: "Your Email Please" %></br>
<%= user.text_field 'address', placeholder: "Your Address Please" %></br>
<%= user.submit "Be Mine Friend", class: "btn btn-primary" %>
<% end %>
</div>
view page for mine_friend
<div class="container">
<p><strong><%= #title %></strong><p>
<%= notice %>
<%= will_paginate #friend, previous_label: "<<", next_label: ">>", class: "pagination pagination-large" %>
<table class="table table table-striped">
<tr>
<th>Name</th>
<th>Address</th>
<th>Email</th>
</tr>
<% #friend.each do |friend| %>
<tr>
<td><%= friend.name %></td>
<td><%= friend.address %></td>
<td><%= friend.email %></td>
</tr>
<% end %>
</table>
</div>
and model is
class User < ActiveRecord::Base
attr_accessible :address, :email, :message, :name
validates :address, :email, :message, :name, presence: :true
end
I while I try to save user from friend_list I get such
Processing by FriendController#be_mine_friend as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"5A1dXtuYJpfqpOphkdl+WA657T3ok2zu/8U1v1B8tEg=", "user"=>{"name"=>"Amritdeep", "email"=>"amritdeepdhungana#hotmail.com", "address"=>"Bou"}, "commit"=>"Be Mine Friend"}
Completed 500 Internal Server Error in 1ms6090>:
the error is
NoMethodError - undefined method `save?' for #<ActiveSupport::HashWithIndifferentAccess:0x00000003c06090>:
What should I do now? Do you guys have any solution for it? I don't know why this ActiveSupport::HashWithIndifferentAccess error is following. Do you guys have any idea about it?
#user = params[:user]
if #user.save?
The params[:user] is a hash. it is not a user object. This is the norm:
#user = User.create(params[:user])

Ruby on Rails: Form won't create hidden_field

I'm trying to create a form with a helper in Rails but all my fields aren't created. I have a helper that I include in my view (I'll include them both). But since I'm new to rails I'm not even sure I'm doing this the right way.
When i write it like this it at first looks like it works since the button is created but when i click it no values are passed and an empty row is created in the DB (except for id and timestamp).
users_helper.rb
module UsersHelper
def sub_button(u)
#current_user = User.find session[:user_id]
#temp_user = u
#sub = Subscription.where("userID = ? AND followingID = ?", #current_user.id, #temp_user.id)
if #sub.blank?
#following = false
else
#following = true
end
if(u.username != #current_user.username)
if #following
form_for(:subscription, :url => { :controller => "subscriptions", :action => "unsubscribe" }) do |s|
s.hidden_field(:userID, :value => #current_user.id)
s.hidden_field(:followingID, :value => u.id)
s.submit "Unfollow"
end
else
form_for(:subscription, :url => { :controller => "subscriptions", :action => "subscribe" }) do |s|
s.hidden_field(:userID, :value => #current_user.id)
s.hidden_field(:followingID, :value => u.id)
s.submit "Follow"
end
end
end
end
end
index.html.erb
<h2>All users</h2>
<table>
<tr>
<th>Username</th>
<th>Email</th>
</tr>
<% #user.each do |u| %>
<tr>
<td><%= u.username %></td>
<td><%= u.email %></td>
<td><%= sub_button(u) %></td>
</tr>
<% end %>
</table>
So I was thinking if I'm missing something to create the fields.. any clues?
I'm not sure, but I think this is how it's supposed to be organized:
module UserHelper
def sub_button u
#current_user = User.find session[:user_id]
#temp_user = u
#sub = Subscription.where("userID = ? AND followingID = ?", #current_user.id, #temp_user.id)
if #sub.blank?
#following = false
else
#following = true
end
if(u.username != #current_user.username)
if #following
render partial: 'shared/unfollow', locals: { current_user: #current_user, u: u }
else
render partial: 'shared/follow', locals: { current_user: #current_user, u: u }
end
end
end
views/shared/_unfollow.html.erb
<%= form_for(:subscription, url: { controller: "subscriptions", action: "unsubscribe" }) do |s| %>
<%= s.hidden_field(:userID, value: current_user.id) %>
<%= s.hidden_field(:followingID, value: u.id) %>
<%= s.submit "Unfollow" %>
<% end %>
views/shared/_follow.html.erb
<%= form_for(:subscription, url: { controller: "subscriptions", action: "subscribe" }) do |s| %>
<%= s.hidden_field(:userID, :value => current_user.id) %>
<%= s.hidden_field(:followingID, :value => u.id) %>
<%= s.submit "Follow" %>
<% end %>

Why this won't pass previous input data when it returns error and redirect?

First of all, I input 'hello' into comment input box and submit it.
It succeeds without any problem.
Then if I try re-do again within 10 seconds, I designed it to returns 'spamming warning'
It does the action as I wished. But the problem is, all the input data I typed in at previous page is gone... so I have to type them all again.
How can I leave the previous input data?
def show
...
#comment_input = #user.comment_threads.build
...
end
def add_comment
#user = User.find_by_username(params[:id])
#post = #user.comment_threads.last
if #post
last_time = #post.created_at
if Time.now - last_time <= 10.second
redirect_to :controller => 'users', :action => 'show', :id => #user.username
flash[:notice] = "You cannot spam!"
return
end
end
#user_who_commented = current_user
#comment = Comment.build_from( #user, #user_who_commented.id, params[:comment][:body] )
#comment.comment_icon = params[:comment][:comment_icon]
#comment.save
redirect_to :controller => 'users', :action => 'show', :id => #user.username
flash[:notice] = "comment added!"
end
_form.html.erb
<%=form_for #comment_input, url: url_for( :controller => :users, :action => :add_comment ) do |f| %>
<div class="field">
<%= f.label :body %><br />
<%= f.text_field :body %>
</div>
<div class="field">
<%= f.file_field :comment_icon %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
UPDATE:
users_controller.rb #show
def show
#user = User.find_by_username(params[:id])
#comments = #user.comment_threads.order("updated_at DESC").page(params[:page]).per(5)
#comment_input = #user.comment_threads.build
respond_to do |format|
format.html # index.html.erb
format.json { render json: #user }
end
end
end
views/users/show.html.erb
.....
<table>
<tr>
<th>ID</th>
<th>PIC</th>
<th>Body</th>
<th>Subject</th>
<th>Posted by</th>
<th>Delete</th>
</tr>
<% #comments.each do |comment| %>
<tr>
<td><%= comment.id %></td>
<td>
<% if comment.comment_icon? %>
<ul class="thumbnails">
<%= image_tag(comment.comment_icon.url(:thumb),:height => 100, :width => 100, :style => 'border:3px double #545565;' ) %>
</ul>
<% end %>
</td>
<td><%= comment.body %></td>
<td><%= comment.subject %></td>
<td><%= comment.user.user_profile.nickname if comment.user.user_profile %></td>
<td>
<%= button_to 'destroy', delete_comment_user_path(#user,comment.id), confirm: 'Are you sure?', :disable_with => 'deleting...' if current_user && current_user.id == comment.user_id %>
</td>
</tr>
<% end %>
</table>
<%=form_for #comment_input, url: url_for( :controller => :users, :action => :add_comment ) do |f| %>
<div class="field">
<%= f.label :body %><br />
<%= f.text_field :body %>
</div>
<div class="field">
<%= f.file_field :comment_icon %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
......
def add_comment
#user = User.find_by_username(params[:id])
#post = #user.comment_threads.last
#user_who_commented = current_user
#comments = #user.comment_threads.order("updated_at DESC").page(params[:page]).per(5)
#comment = Comment.build_from( #user, #user_who_commented.id, params[:comment][:body] )
#comment.comment_icon = params[:comment][:comment_icon]
if #post && (Time.now - #post.created_at) <= 10.second
flash[:notice] = "You cannot spam!"
render :action => "show"
elsif #comment.save
flash[:notice] = "comment added!"
redirect_to :controller => 'users', :action => 'show', :id => #user.username
else # if model's errors
render :action => "show"
end
end

Resources