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
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.
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
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])
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 %>
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