How best to deal with HTTP response in Ruby? - ruby

I'm using ActiveModel instead of ActiveRecord. And my model is:
class User
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
validates :name, :presence => true, :length => { :maximum => 50 }
validates :email, :presence => true,
:format =>
{
:with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
}
validates :password, :presence => true, :confirmation => true,
:length =>
{
:within => 6..40
}
attr_accessor :name, :email, :password, :password_confirmation
def initialize(attributes = {})
#name = attributes[:name]
#email = attributes[:email]
#password = attributes[:password]
#password_confirmation = attributes[:password_confirmation]
end
def persisted?
false
end
def save
# createUser calls RESTful HTTP server and gets back JSON in http response's body
response = createUser(self.name, self.email, self.password)
end
end
And in my users_controller.rb below when I try to process this response returned by save method above, it messes up my model's validations for password and password_confirmation.
def create
#user = User.new(params[:user])
response = #user.save
parsed_response_body = ActiveSupport::JSON.decode(response.body)
# response body I have is {"ok":"ok message"} OR {"error":"error message"}
message = parsed_response_body["error"]
if #user.valid? && message.nil?
flash[:success] = message
redirect_to signup_path
else
#user.password = ""
#user.password_confirmation = ""
flash[:error] = message
render :action => 'new'
end
end
And below is controller code that doesn't break the validations; where #user.save in this case is returning true.
def create
#user = User.new(params[:user])
if #user.valid? && #user.save
flash[:success] = "Done"
redirect_to signup_path
else
#user.password = ""
#user.password_confirmation = ""
flash[:error] = "Not Done"
render :action => 'new'
end
end
I'd be thankful if someone can help me with this..

It looks to me like you need to call super in save or it won't actually try to validate:
def save
super
# createUser calls RESTful HTTP server and gets back JSON in http response's body
response = createUser(self.name, self.email, self.password)
end

Related

New password could not set into DB using Ruby on Rails 3

I am trying to reset the new password using Rails 3.When i insert new password(i.e.123456789) and clicked on submit button it gave me the following error.
Error:
NoMethodError in HomesController#resubmitpass
undefined method `stringify_keys' for "123456789":String
Rails.root: C:/Site/library_management1
Application Trace | Framework Trace | Full Trace
app/controllers/homes_controller.rb:179:in `resubmitpass'
Please check my below codes and let me to know how it will be solved ?
views/homes/resetpass.html.erb
<center>
<%= form_for :users,:url => {:action =>'resubmitpass',:id =>params[:id] } do |f| %>
<div class="pass-div">
<p>
<%= f.password_field :password,:id => "pre-pass",placeholder:"Enter your new password" %>
</p>
<p>
<%= f.password_field :password_confirmation ,:id => "pre-pass", placeholder:"Enter your password again" %>
</p>
<p>
<%= f.submit 'Update',:class => "btn btn-success" %>
</p>
</div>
<% end %>
</center>
controller/homes_controller.rb
class HomesController < ApplicationController
before_filter :authenticate_admin!,only: [:admin]
def index
end
def admin
end
def managebooks
#books=Book.new
if params[:id]
#books=Book.find(params[:id])
#book=Book.all
end
end
def savebooks
#books=Book.new(params[:books])
if #books.save
flash[:notice]="Data has submitted successfully"
flash[:color]="valid"
redirect_to :action => 'managebooks',:id => #books.id
else
flash[:notice]="Data couldnot submitted successfully"
flash[:color]="invalid"
render 'managebooks'
end
end
def remove
#books=Book.find(params[:id])
#books.destroy
end
def books
end
def showbooks
#books=Book.all
end
def searchbooks
#books=Book.all
end
def member
#users=User.new
end
def registration
#users=User.new
end
def savedata
#users=User.new(params[:users])
if #users.save
flash[:notice]="Data has submitted successfully"
flash[:color]="valid"
redirect_to :action => 'member'
else
flash[:notice]="Data could not submitted successfully"
flash[:color]="invalid"
render 'registration'
end
end
def issuebooks
#issues=Issue.new
end
def savedissuebooks
#issues=Issue.new(params[:issues])
if #issues.save
flash[:notice]="information has saved successfully"
flash[:color]="valid"
redirect_to :action => 'member'
else
flash[:notice]="Data couldnot saved"
flash[:color]="invalid"
render 'issuebooks'
end
end
def availablebooks
#books=Book.all
end
def userissues
#issues=Issue.all
end
def magazine
#magazines=Magazine.new
end
def savemagazines
#users=User.find(params[:id])
#magazines=Magazine.new(params[:magazines])
#magazines.user_id=#users.id
if #magazines.save
flash[:notice]="Data submitted successfully"
flash[:color]="valid"
redirect_to :action => "member"
else
flash[:notice]="Data could not saved"
flash[:color]="invalid"
render 'magazines'
end
end
def magazineissue
#magazines=Magazine.all
#users=User.find #magazines.first.user_id
end
def blog
#blogs=Blog.new
end
def savecomments
#users=User.find(params[:id])
#blogs=Blog.new(params[:blogs])
#blogs.user_id=#users.id
if #blogs.save
flash[:notice]="Comment has been posted successfully"
flash[:color]="valid"
redirect_to :action => "showcomment"
else
flash[:notice]="Comment could not saved"
flash[:color]="invalid"
render 'blog'
end
end
def showcomment
#blogs=Blog.all
end
def newspaper
#newspapers=Newspaper.new
end
def savenewspaper
#users=User.find(params[:id])
#newspapers=Newspaper.new(params[:newspapers])
#newspapers.user_id=#users.id
if #newspapers.save
flash[:notice]="newspaper data saved successfully"
flash[:color]="valid"
redirect_to :action => "member"
else
flash[:alert]="Data could not saved successfully"
flash[:color]="invalid"
render 'newspaper'
end
end
def adminnewspaperissue
#newspapers=Newspaper.all
#users=User.find #newspapers.first.user_id
end
def userprofile
#users=User.find(params[:id])
end
def updatedata
#users=User.find(params[:id])
if #users.update_attributes(params[:users])
flash[:notice]="User Data has updated"
flash[:color]="valid"
redirect_to :action => 'member'
else
flash[:alert]="Data could not updated"
flash[:color]="invalid"
render 'userprofile'
end
end
def forgetpass
#users=User.new
end
def sendemail
#users=User.find_by_email(params[:users][:email])
if #users.email==params[:users][:email]
UserMailer.registration_confirmation(#users).deliver
flash[:notice]="check your mail to reset your password"
flash[:color]="valid"
redirect_to :action => "checkmail"
else
flash[:alert]="You might entered wrong email address"
flash[:color]="invalid"
render 'forgetpass'
end
end
def resetpass
#users=User.new
end
def resubmitpass
#users=User.find(params[:id])
if #users.update_attributes(params[:users][:password])
flash[:notice]="Your password updated succesfully"
flash[:color]="valid"
redirect_to :action => "member"
else
flash[:alert]="Your password could not updated successfully"
flash[:color]="invalid"
render 'resetpass'
end
end
end
model/user.rb
class User < ActiveRecord::Base
attr_accessible :address, :email, :first_name, :last_name, :password, :password_hash, :password_salt, :tel_no ,:password_confirmation
attr_accessor :password
before_save :encrypt_password
EMAIL_REGEX = /\A[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\z/i
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX
validates :first_name, :presence => true, :length => {:in => 3..10}
validates :last_name , :presence => true , :length => {:in => 3..10}
validates :tel_no , :presence => true , :length => {:in => 1..10}
validates :password, :confirmation => true
validates_length_of :password, :in => 6..20, :on => :create
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
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
has_many :issue
has_many :book
has_many :magazine
has_many :blog
has_many :newspaper
end
db/migrate/20150311112733_create_users.rb
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email
t.string :password
t.string :tel_no
t.string :address
t.string :password_hash
t.string :password_salt
t.timestamps
end
end
end
Actually the error is coming in this line "if #users.update_attributes(params[:users][:password])".Please help me to resolve this error.
It is happening because you are using update_attributes incorrectly.
You need to specifically pass the params to the associated column like update_attributes(:password => params[:password]) or better use Object.update_attribute(:only_one_field, "Some Value")
If you want to pass the whole params hash you can simply use this:
update_attributes(params[:user]).
You can read more about it here.

declare value for strong parameters

i have problem when i have to declare value for one of parameters in my permit and out of post form values .
look at my code :
class QuoteController < ApplicationController
autocomplete :author, :name, :full => true
autocomplete :Category, :title, :full => true
def new
#quotes = Quote.new
end
def create
#quotes = Quote.new(quotesParams)
if #quotes.save
redirect_to root_url
else
redirect_to root_url
end
end
private
def quotesParams
params.require(:quote).permit(:text,:author_id, :category_id,
{:send_type => ["web"]},
{:user_id => [current_user.id])
end
end
but when i try to save in database send_type and user_id is null
Strong parameters is more about the structure of the parameters than the actual parameter values. So things like:
{ :send_type => ["web"] }
{ :user_id => [current_user.id] }
don't assign default values, they're specifying the structure of nested values in params.
I think you should handle your defaults in two places:
send_type should default to 'web' inside the model.
user_id should be required by the model but the controller should set the default (because that's who knows about current_user.
Something like this in your controller:
def create
#quotes = Quote.new(quotesParams) { |q| q.user_id = current_user.id }
#...
end
def quotesParams
params.require(:quote).permit(:text, :author_id, :category_id, :send_type)
end
and your model can default send_type to 'web' if the controller doesn't supply a value.
Try the following code for your controller:
class QuoteController < ApplicationController
autocomplete :author, :name, :full => true
autocomplete :Category, :title, :full => true
def new
#quotes = Quote.new
end
def create
#quotes = Quote.new(quotesParams)
#quotes.send_type = "web"
#quotes.user_id = current_user.id
if #quotes.save
redirect_to root_url
else
redirect_to root_url
end
end
private
def quotesParams
params.require(:quote).permit(:text, :author_id, :category_id)
end
end

undefined method `password_hash' error with datamapper

I'm trying to build [Ryan Bates' "authenticaion from scratch"][1] using sinatra but authentication does not work. I get a "undefined method password_hash" error.
Everything else is working. I checked datamapper documentation, especially for lazy loading, but couldn't find anything useful. The code is below. What mistake am I doing?
main.rb (only relevant part)
post "/login" do
user = User.authenticate params[:email], params[:password]
if user
session[:user_id] = user.id
redirect "/"
else
session[:errors] = "No such user or bad password."
redirect "/login"
end
end
user.rb
require 'data_mapper'
require 'dm-validations'
require 'bcrypt'
module Kimsin
DataMapper.setup :default, 'sqlite3:///home/barerd/RProjects/kimsin/users.db'
class User
attr_accessor :password, :confirm_password
include DataMapper::Resource
property :id, Serial
property :email, String, :required => true, :unique => true, :format => :email_address,
:messages => { :presence => "We need your email address.", :is_unique => "We already have that email.", :format => "Doesn't look like an email adress.."}
property :password_salt, String
property :password_hash, String, :length => 80
validates_presence_of :password, :confirm_password, :messages => { :presence => "You have to type a password and confirm it." }
validates_format_of :password, :confirm_password, :with => /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])([\x20-\x7E]){8,40}$/, :messages => { :format => "The password should be 8 to 40 characters long and contain at least one digit, one lowercase and one uppercase letter and one special character." }
before :save, :encrypt_password
def self.authenticate email, password
user = User.all :email.like => email
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password != nil
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret password, password_salt
end
end
end
DataMapper.finalize
end
Adding a attr_reader :password_hash solved it.

Rails form validation works in one template but not another for the same Model

Another hair-puller. AFter two days of fighting with this I cannot figure out what is wrong here.
Basically I have a form validation triggered by the model:
validates :user, :presence => true, :uniqueness => true
validates :email, :presence => true, :uniqueness => true, :on => :create
validates :passwordHash, :presence => true, :confirmation => true, :on => :create
The user not being empty works on the update form View:
= simple_form_for #user do |f|
= f.input :user
= f.input :locale
= f.input :localeLanguage, :label => 'Language', :as => :select, :collection => $language_array
= f.input :moderator
= f.input :email
= f.input :passwordHash, :label => 'Password'
But not on the new users View:
= simple_form_for #user do |f|
%table.table-condensed
%tr
%td
=f.input :user, :label => false, :placeholder => 'username'
%tr
%td
= f.input :passwordHash, :label => false, :placeholder => 'password'
%tr
%td
= f.input :email, :label => false, :placeholder => 'email'
%tr
%td
= f.submit "Create User", :class => 'btn btn-primary'
The only difference I can see between these views is that the first one has sessions created since a user has already logged in, the second one doesn't. But as far as I know this should not make a difference. Of course, the update form does have an actual #user object whereas in the new one it is empty. But I've seen Ryan Bates' railscast of a new user validation and he does pretty much the same thing.
What happens is the users#create action being invoked after submitting the form with empty values (which should not be possible). Of course I get an error because the passwordHash is empty.
I should point out that I'm not using any extra gems to aid in password confirmation (in the railscast, Bates uses bcrypt but I can't use it because we create the password hash a different way plus I think that's for the password confirmation magic only). In any case this should not affect the form validation should it?
Any theories or ideas are welcome here, I'm going crazy. I'm about to write some crappy javascript to do it by hand which would be awful and would probably take me a week, I don't do javascript ;)
Thanks.
Edit
Per Rachid's request, here are the new and create actions:
def new
#user = User.new
end
def create
#failsafe for failing form validation
unless params[:passwordHash].present?
redirect_to new_user_path, :notice => 'User or password cannot be blank'
else
password_and_salt = User.hash_password(params[:passwordHash])
hashed_password = password_and_salt[:password]
user_salt = password_and_salt[:salt]
#user = User.new(:user => params[:user], :passwordHash => hashed_password, :salt => user_salt)
if #user.save
session[:user_id] = #user.id
redirect_to session[:item_to_edit]
else
redirect_to new_user_path, :notice => "User already exists, please pick another one"
end
end
end
Edit 2
I've rewritten the create method based on the first answer, but still getting an error:
def create
respond_to do |format|
if params[:passwordHash].present? && params[:user].present?
password_and_salt = User.hash_password(params[:passwordHash])
hashed_password = password_and_salt[:password]
user_salt = password_and_salt[:salt]
#user = User.new(:user => params[:user], :passwordHash => hashed_password, :salt => user_salt, :online_user => 1 )
if #user.save
session[:user_id] = #user.id
redirect_to session[:item_to_edit]
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
The error is undefined method 'model_name' for NilClass:Class for this line:
= simple_form_for #user do |f|
Obviously the #user = User.new is not making it back to the form. At this point I'm a little confused as to how I should write the create method for it to work properly and show the error messages. But I feel I'm closer :)
#misha, here is the update controller action, it's just pretty standard scaffolding:
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
if session[:return_to]
format.html { redirect_to session[:return_to], :notice => 'User was successfully updated.' }
else
format.html { redirect_to users_path, :notice => 'User was successfully updated.' }
end
format.json { head :ok }
else
format.html { render :action => "edit" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
First of all what you assume here is incorrect:
What happens is the users#create action being invoked after submitting
the form with empty values (which should not be possible). Of course I
get an error because the passwordHash is empty.
It is possible that users#create is invoked and actually it should happen. It is in the create action where you handle this stuff. I think your problem is the fact that you do a redirect if the #user is not saved. You should render the view again, so the error messages can be displayed.
So instead of:
redirect_to new_user_path, :notice => "User already exists, please pick another one"
Try:
render :action => 'new'
Edit based on your comment:
When validation fails Rails populates #user.errors automatically. You don't have to do anything in the controller (i.e. your create action)! All you have to do is display the errors in #user.errors in your view.
About the error you are getting now:
The reason you are getting the error is that #user is not set. You have to rewrite your create method to something like this:
def create
respond_to do |format|
if params[:user][:passwordHash].present?
password_and_salt = User.hash_password(params[:user][:passwordHash])
hashed_password = password_and_salt[:password]
user_salt = password_and_salt[:salt]
end
#user = User.new(params[:user].merge({:passwordHash => hashed_password, :salt => user_salt, :online_user => 1}))
if #user.save
session[:user_id] = #user.id
redirect_to session[:item_to_edit]
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end

RoR Tutorial (Chapter 10.4) - admin attributes tests fail

I'm a RoR-Learner and I made my way to the RoR-Tutorial by Michael Hartl, but actually I'm facing a problem at Chapter 10.4. I did all the Listings up to 10.42, but 3 of my Rspec-Tests are failing.
It says:
1) Users admin attribute should respond to admin
Failure/Error: #user = User.create!(#attr)
ActiveRecord::RecordInvalid: Validation failed: Name can't be blank,
Email can't be blank, Email is invalid, Password can't be blank,
Password is too short (minimum is 6 characters)
./spec/requests/users_spec.rb:52:in `block (3 levels) in
2) Users admin attribute should not be an admin by default
Failure/Error: #user = User.create!(#attr)
ActiveRecord::RecordInvalid: Validation failed: Name can't be blank,
Email can't be blank, Email is invalid, Password can't be blank,
Password is too short (minimum is 6 characters)
./spec/requests/users_spec.rb:52:in `block (3 levels) in
3) Users admin attribute should be convertible to an admin
Failure/Error: #user = User.create!(#attr)
ActiveRecord::RecordInvalid: Validation failed: Name can't be blank,
Email can't be blank, Email is invalid, Password can't be blank,
Password is too short (minimum is 6 characters)
./spec/requests/users_spec.rb:52:in `block (3 levels) in
I already took a careful look on my users_controllers_spec.rb and my user_spec.rb, but I couldn't find an explanation for the mistakes. Does anyone have an idea?
require 'spec_helper'
describe UsersController do
render_views
describe "GET 'index'" do
describe "for non-signed-in users" do
it "should deny access" do
get :index
response.should redirect_to(signin_path)
flash[:notice].should =~ /sign in/i
end
end
describe "for signed-in users" do
before(:each) do
#user = test_sign_in(Factory(:user))
second = Factory(:user, :name => "Bob", :email => "another#example.com")
third = Factory(:user, :name => "Ben", :email => "another#example.net")
##users = [#user, second, third]
#users = [#user, second, third]
30.times do
#users << Factory(:user, :name => Factory.next(:name),
:email => Factory.next(:email))
end
end
it "should be successful" do
get :index
response.should be_success
end
it "should have the right title" do
get :index
response.should have_selector("title", :content => "All users")
end
it "should have an element for each user" do
get :index
#users[0..2].each do |user|
response.should have_selector("li", :content => user.name)
end
end
it "should paginate users" do
get :index
response.should have_selector("div.pagination")
response.should have_selector("span.disabled", :content => "Previous")
response.should have_selector("a", :href => "/users?escape=false&page=2",
:content => "2")
response.should have_selector("a", :href => "/users?escape=false&page=2",
:content => "Next")
end
end
end
describe "GET 'show'" do
before(:each) do
#user = Factory(:user)
end
it "should be successful" do
get :show, :id => #user
response.should be_success
end
it "should find the right user" do
get :show, :id => #user
assigns(:user).should == #user
end
it "should have the right title" do
get :show, :id => #user
response.should have_selector("title", :content => #user.name)
end
it "should include the user's name" do
get :show, :id => #user
response.should have_selector("h1", :content => #user.name)
end
it "should have a profile image" do
get :show, :id => #user
response.should have_selector("h1>img", :class => "gravatar")
end
end
describe "GET 'new'" do
it "should be successful" do
get 'new'
response.should be_success
end
it "should have the right title" do
get 'new'
response.should have_selector("title", :content => "Sign up")
end
end
describe "POST 'create'" do
describe "failure" do
before(:each) do
#attr = { :name => "", :email => "", :password => "",
:password_confirmation => "" }
end
it "should not create a user" do
lambda do
post :create, :user => #attr
end.should_not change(User, :count)
end
it "should have the right title" do
post :create, :user => #attr
response.should have_selector("title", :content => "Sign up")
end
it "should render the 'new' page" do
post :create, :user => #attr
response.should render_template('new')
end
end
describe "success" do
before(:each) do
#attr = { :name => "New User", :email => "user#example.com",
:password => "foobar", :password_confirmation => "foobar" }
end
it "should create a user" do
lambda do
post :create, :user => #attr
end.should change(User, :count).by(1)
end
it "should redirect to the user show page" do
post :create, :user => #attr
response.should redirect_to(user_path(assigns(:user)))
end
it "should have a welcome message" do
post :create, :user => #attr
flash[:success].should =~ /welcome to the sample app/i
end
it "should sign the user in" do
post :create, :user => #attr
controller.should be_signed_in
end
end
end
describe "GET 'edit'" do
before(:each) do
#user = Factory(:user)
test_sign_in(#user)
end
it "should be successful" do
get :edit, :id => #user
response.should be_success
end
it "should have the right title" do
get :edit, :id => #user
response.should have_selector("title", :content => "Edit user")
end
it "should have a link to change the Gravatar" do
get :edit, :id => #user
gravatar_url = "http://gravatar.com/emails"
response.should have_selector("a", :href => gravatar_url,
:content => "change")
end
end
describe "PUT 'update'" do
before(:each) do
#user = Factory(:user)
test_sign_in(#user)
end
describe "failure" do
before(:each) do
#attr = { :email => "", :name => "", :password => "",
:password_confirmation => "" }
end
it "should render the 'edit' page" do
put :update, :id => #user, :user => #attr
response.should render_template('edit')
end
it "should have the right title" do
put :update, :id => #user, :user => #attr
response.should have_selector("title", :content => "Edit user")
end
end
describe "success" do
before(:each) do
#attr = { :name => "New Name", :email => "user#example.org",
:password => "barbaz", :password_confirmation => "barbaz" }
end
it "should change the user's attributes" do
put :update, :id => #user, :user => #attr
#user.reload
#user.name.should == #attr[:name]
#user.email.should == #attr[:email]
end
it "should redirect to the user show page" do
put :update, :id => #user, :user => #attr
response.should redirect_to(user_path(#user))
end
it "should have a flash message" do
put :update, :id => #user, :user => #attr
flash[:success].should =~ /updated/
end
end
end
describe "authentication of edit/update pages" do
before(:each) do
#user = Factory(:user)
end
describe "for non-signed-in users" do
it "should deny access to 'edit'" do
get :edit, :id => #user
response.should redirect_to(signin_path)
end
it "should deny access to 'update'" do
put :update, :id => #user, :user => {}
response.should redirect_to(signin_path)
end
end
describe "for signed-in users" do
before(:each) do
wrong_user = Factory(:user, :email => "user#example.net")
test_sign_in(wrong_user)
end
it "should require matching users for 'edit'" do
get :edit, :id => #user
response.should redirect_to(root_path)
end
it "should require matching users for 'update'" do
put :update, :id => #user, :user => {}
response.should redirect_to(root_path)
end
end
end
describe "DELETE 'destroy'" do
before(:each) do
#user = Factory(:user)
end
describe "as a non-signed-in user" do
it "should deny access" do
delete :destroy, :id => #user
response.should redirect_to(signin_path)
end
end
describe "as a non-admin user" do
it "should protect the page" do
test_sign_in(#user)
delete :destroy, :id => #user
response.should redirect_to(root_path)
end
end
describe "as an admin user" do
before(:each) do
admin = Factory(:user, :email => "admin#example.com", :admin => true)
test_sign_in(admin)
end
it "should destroy the user" do
lambda do
delete :destroy, :id => #user
end.should change(User, :count).by(-1)
end
it "should redirect to the users page" do
delete :destroy, :id => #user
response.should redirect_to(users_path)
end
end
end
end
This is my user_spec.rb
require 'spec_helper'
describe User do
before(:each) do
#attr = {
:name => "Example User",
:email => "user#example.com",
:password => "foobar",
:password_confirmation => "foobar"
}
end
it "should create a new instance given valid attributes" do
User.create!(#attr)
end
it "should require a name" do
no_name_user = User.new(#attr.merge(:name => ""))
no_name_user.should_not be_valid
end
it "should require an email address" do
no_email_user = User.new(#attr.merge(:email => ""))
no_email_user.should_not be_valid
end
it "should reject names that are too long" do
long_name = "a" * 51
long_name_user = User.new(#attr.merge(:name => long_name))
long_name_user.should_not be_valid
end
it "should accept valid email addresses" do
addresses = %w[user#foo.com THE_USER#foo.bar.org first.last#foo.jp]
addresses.each do |address|
valid_email_user = User.new(#attr.merge(:email => address))
valid_email_user.should be_valid
end
end
it "should reject invalid email addresses" do
addresses = %w[user#foo,com user_at_foo.org example.user#foo.]
addresses.each do |address|
invalid_email_user = User.new(#attr.merge(:email => address))
invalid_email_user.should_not be_valid
end
end
it "should reject duplicate email addresses" do
# Put a user with given email address into the database.
User.create!(#attr)
user_with_duplicate_email = User.new(#attr)
user_with_duplicate_email.should_not be_valid
end
it "should reject email addresses identical up to case" do
upcased_email = #attr[:email].upcase
User.create!(#attr.merge(:email => upcased_email))
user_with_duplicate_email = User.new(#attr)
user_with_duplicate_email.should_not be_valid
end
describe "password validations" do
it "should require a password" do
User.new(#attr.merge(:password => "", :password_confirmation => "")).
should_not be_valid
end
it "should require a matching password confirmation" do
User.new(#attr.merge(:password_confirmation => "invalid")).
should_not be_valid
end
it "should reject short passwords" do
short = "a" * 5
hash = #attr.merge(:password => short, :password_confirmation => short)
User.new(hash).should_not be_valid
end
it "should reject long passwords" do
long = "a" * 41
hash = #attr.merge(:password => long, :password_confirmation => long)
User.new(hash).should_not be_valid
end
end
describe "password encryption" do
before(:each) do
#user = User.create!(#attr)
end
it "should have an encrypted password attribute" do
#user.should respond_to(:encrypted_password)
end
it "should set the encrypted password" do
#user.encrypted_password.should_not be_blank
end
describe "has_password? method" do
it "should be true if the passwords match" do
#user.has_password?(#attr[:password]).should be_true
end
it "should be false if the passwords don't match" do
#user.has_password?("invalid").should be_false
end
end
end
describe "authenticate method" do
it "should return nil on email/password mismatch" do
wrong_password_user = User.authenticate(#attr[:email], "wrongpass")
wrong_password_user.should be_nil
end
it "should return nil for an email address with no user" do
nonexistent_user = User.authenticate("bar#foo.com", #attr[:password])
nonexistent_user.should be_nil
end
it "should return the user on email/password match" do
matching_user = User.authenticate(#attr[:email], #attr[:password])
matching_user.should == #user
end
end
describe "admin attribute" do
before(:each) do
#user = User.create!({
:name => "Example User",
:email => "user#example.com",
:password => "foobar",
:password_confirmation => "foobar"
})#(#attr)
//EDIT: I tried both, the fill-in by hand an the original code with (#attr) --> nothing changes, still the same mistake
end
it "should respond to admin" do
#user.should respond_to(:admin)
end
it "should not be an admin by default" do
#user.should_not be_admin
end
it "should be convertible to an admin" do
#user.toggle!(:admin)
#user.should be_admin
end
end
end
EDIT: User.rb
== Schema Information
Table name: users
id :integer not null, primary key
name :string(255)
email :string(255)
created_at :datetime
updated_at :datetime
//it's outcommented
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
before_save :encrypt_password
def has_password?(submitted_password)
encrypted_password == encrypt(submitted_password)
end
def self.authenticate_with_salt(id, cookie_salt)
user = find_by_id(id)
(user && user.salt == cookie_salt) ? user : nil
end
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
private
def encrypt_password
self.salt = make_salt unless has_password?(password)
self.encrypted_password = encrypt(password)
end
def encrypt(string)
secure_hash("#{salt}--#{string}")
end
def make_salt
secure_hash("#{Time.now.utc}--#{password}")
end
def secure_hash(string)
Digest::SHA2.hexdigest(string)
end
end
If some important details are missing, please ask, I'm prepared to update this post (just didn't want to overload it, because the code is already huge enough).
Thanks for your attention!
I have just recently come across this same issue and resolved it by removing the bang (!) from the create method call:
#user = User.create(#attr)
HTH
Your user_spec.rb does not match with the one from Listing 10.34 in the tutorial.
More specifically, the before(:each) block.
your user_spec.rb:
before(:each) do
#user = User.create!({
:name => "Example User",
:email => "user#example.com",
:password => "foobar",
:password_confirmation => "foobar"
})#(#attr)
end
Listing 10.34:
before(:each) do
#user = User.create!(#attr)
end

Resources