I'm just following Ruby on Rails 3 Tutorials (Mhartl) chapter-7 at the stage of 7.3.2 name and Gravatar.
Here I am facing a problem when I open on my browser it's says:
ActiveRecord::RecordNotFound in UsersController#show
Couldn't find User with id=1
Rails.root: C:/RubyOnRails/MyWorkPlace/sample_app_1
Application Trace | Framework Trace | Full Trace
app/controllers/users_controller.rb:5:in `show'
Request
Parameters:
{"id"=>"1"}
Show session dump
Show env dump
Response
Headers:
None
Also I pasted below User_controller.rb and user.rb
user.rb:
require 'digest'
class User < ActiveRecord::Base
attr_accessor :pasword
attr_accessible :login,
:username,
:email,
:password,
:password_confirmation,
:remember_me
email_regex = /\A[\w+\-.]+#[a-z\-.]+\.[a-z]+\z/i
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
validates :pasword, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
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
before_save :encrypt_password
def has_password?(submitted_password)
encrypted_password == encrypt(submitted_password)
end
private
def encrypt_password
self.salt = make_salt if new_record?
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
users_controller.rb:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#title = #user.name
end
def new
#title = "Sign up"
end
end
Are you sure you created any user with id=1 ?
To check, go to rails console and get the user with id 1. If there is no user, then create one.
At firest, I see you have attr_accessor :pasword
I think it should be :password
Ontopic:
There are some actions missing in the restful controller, so it wont be possible to create a user.
See http://guides.rubyonrails.org/getting_started.html#rest for more details on RESTful controllers.
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#title = #user.name
end
def new
#user = User.new #this creates a empty user object to be filled with signup data
#title = "Sign up"
end
def create
#user = User.new(params[:user]) #this creates a new user object with the data you entered before.
if #user.save #if the data is valid, save it
redirect_to user_path(#user) #and go to the #user show action
else
render :action => :new #edit the invalid user data
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
redirect_to user_url(#user)
else
render edit_user_url(#user)
end
end
def index
#users = User.all
end
def destroy
#user = User.find(params[:id]
#user.destroy
redirect_to :action => :index
end
end
edit: complete restful actions
I had the same problema. In my case, my 'redirect_to' on my detroy action was missin a 's' in 'posts_path'. It was post_path Noob, but worth i had checked up.
The reason you could not find the "user/1" is when you Added microposts to the sample data(db/seeds.rb) by typing
users = User.order(:created_at).take(6)
50.times do
content = Faker::Lorem.sentence(5)
users.each { |user| user.microposts.create!(content: content) }
end
You forgot the "END" of the previous code, so the full picture of db/seeds.rb is
User.create!(name: "Example User",
email: "example#railstutorial.org",
password: "foobar",
password_confirmation: "foobar",
admin: true,
activated: true,
activated_at: Time.zone.now)
99.times do |n|
name = Faker::Name.name
email = "example-#{n+1}#railstutorial.org"
password = "password"
User.create!(name: name,
email: email,
password: password,
password_confirmation: password,
activated: true,
activated_at: Time.zone.now)
end
users = User.order(:created_at).take(6)
50.times do
content = Faker::Lorem.sentence(5)
users.each { |user| user.microposts.create!(content: content) }
end
Related
I’m using clearance and love it, but I'm having trouble resetting passwords. I type in my email to reset the password, which works, but then when I try to navigate to the edit password page using the reset token, I get the failure when forbidden flash error “Please double check the URL or try submitting the form again” and it redirects me back. I get the same error in my tests.
I think this has something to do with my before_action statements, but I just don’t know how to fix them. I have researched questions like this to no avail.
I'm sure it's a stupid question, but I'm new so I really appreciate any help. Please let me know if this isn't enough code.
class UsersController < Clearance::UsersController
before_action :require_login, only: [:create] # does this need to be in both user controllers?
...
def user_params
params.require(:user)
end
end
And here is the clearance controller.
class Clearance::UsersController < ApplicationController
before_action :require_login, only: [:create]
require 'will_paginate/array'
def new
#user = user_from_params
render template: 'users/new'
end
def create
#user = user_from_params
#user.regenerate_password
if #user.save
sign_in #user unless current_user
UserMailer.welcome_email(#user).deliver!
redirect_to users_path
else
render template: 'users/new'
end
end
def edit
#user = User.friendly.find(params[:id])
end
def update
#user = User.friendly.find(params[:id])
if #user.update(permit_params)
redirect_to #user
flash[:success] = "This profile has been updated."
else
render 'edit'
end
end
private
def avoid_sign_in
redirect_to Clearance.configuration.redirect_url
end
def url_after_create(user)
dashboards_path(user)
end
def user_from_params
user_params = params[:user] || Hash.new
is_public = check_public_params(user_params)
first_name = user_params.delete(:first_name)
last_name = user_params.delete(:last_name)
email = user_params.delete(:email)
password = user_params.delete(:password)
parish = user_params.delete(:parish)
division = user_params.delete(:division)
admin = user_params.delete(:admin)
Clearance.configuration.user_model.new(user_params).tap do |user|
user.first_name = first_name
user.last_name = last_name
user.password = password
user.email = email
user.is_public = is_public
user.parish_id = parish.to_i
user.division = division
user.admin = admin
end
end
def permit_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :is_public, :parish_id, :division, :admin)
end
end
EDIT: relevant portions of routes.rb
Rails.application.routes.draw do
resources :passwords, controller: "clearance/passwords", only: [:create, :new]
resource :session, controller: "clearance/sessions", only: [:create]
resources :users, controller: "clearance/users", only: [:create] do
resource :password,
controller: "clearance/passwords",
only: [:create, :edit, :update]
end
get "/sign_in" => "clearance/sessions#new", as: "sign_in"
delete "/sign_out" => "clearance/sessions#destroy", as: "sign_out"
get "/sign_up" => "clearance/users#new", as: "sign_up"
constraints Clearance::Constraints::SignedOut.new do
root to: 'high_voltage/pages#show', id: 'landing'
end
constraints Clearance::Constraints::SignedIn.new do
# root to: 'dashboards#index', as: :signed_in_root
root to: 'high_voltage/pages#show', id: 'parish_dashboard', as: :signed_in_root
end
# constraints Clearance::Constraints::SignedIn.new { |user| user.admin? } do
# root to: 'teams#index', as: :admin_root
# end
resources :users do
collection { post :import }
end
It turns out there was a conflict between the way I was finding the user instance in the password reset link. Clearance finds users simply by using #user, but since I'm using FriendlyId I needed to change that to #user.id.
So instead of...
<%= link_to 'Change My Password', edit_user_password_url(#user, token: #user.confirmation_token.html_safe) %>
I did
<%= link_to 'Change My Password', edit_user_password_url(#user.id, token: #user.confirmation_token.html_safe) %>
Thanks, Thoughbot, for this great gem!
I am trying to get some controller tests passing but when they hit the update and delete action, CanCan keeps throwing the Access Denied error despite being set in the abilities. These errors only seem to occur for members, as admins work fine.
Abilities.rb
def initialize(user)
if user.has_role? :admin
can :manage, :all
elsif user.has_role? :member
can :manage, PaymentMethod, :user_id => user.id
end
end
User_Factory
FactoryGirl.define do
factory :user do
sequence(:first_name) { |n| "John_#{n}" }
sequence(:last_name) { |n| "Rambo_#{n}" }
sequence(:email) { |n| "john_rambo_#{n}#example.com" }
sequence(:username) { |n| "john_rambo_#{n}" }
date_of_birth "03/12/1982"
password 'password'
password_confirmation 'password'
picture_url File.open('spec/support/pictures/test.png')
address
factory :member do
sequence(:last_name) { |n| "Member_#{n}" }
roles :member
end
end
end
Controller_Spec.rb
describe "PUT /api/users/:user_id/payment_method/:id" do
before(:each) do
#user = FactoryGirl.create(:member)
sign_in_user #user
#payment_method = FactoryGirl.create(:credit_card, {:user_id => #user.id})
end
it "updates a users payment method" do
attr_to_change = {
brand: "mastercard",
user_id: #user.id,
id: #payment_method.id
}
put :update, attr_to_change
response.status.should == 200
JSON.parse(response.body)["payment_method"]["brand"]
.should == "mastercard"
end
end
describe "DELETE /api/users/:user_id/payment_methods/:id" do
before(:each) do
#user = FactoryGirl.create(:member)
sign_in_user #user
#payment_method = FactoryGirl.create(:credit_card, {:user_id => #user.id})
end
it "destroys a users payment method" do
delete :destroy, {:user_id => #user, :id => #payment_method.id}
response.status.should == 200
end
end
Controller
class Api::PaymentMethodsController < Api::ApiController
before_filter :clean_params, only: [:update, :create]
def index
#user = User.find(params["user_id"])
render json: #user.payment_methods
end
def update
pm_id = params.delete("id")
params.delete("user_id")
#payment_method = PaymentMethod.find(pm_id)
if #payment_method.update_attributes(params)
return render status: 200, json: #payment_method, root: :payment_method
else
return render status: 422, json: {success: false, errors: #payment_method.errors.full_messages.map{|error|{error: error}}}
end
end
def create
#payment_method = PaymentMethod.create_payment_method(params)
if #payment_method
render json: #payment_method, root: :payment_method
else
return render status: 422, json: {success: false, errors: #payment_method.errors.full_messages.map{|error|{error: error}}}
end
end
def destroy
#payment_method = PaymentMethod.find(params["id"])
if #payment_method.destroy
return render status: 200, json: {:message => "PaymentMethod Destroyed"}
else
return render status: 422, json: {success: false, errors: #payment_method.errors.full_messages.map{|error|{error: error}}}
end
end
def clean_params
["controller", "action"].each do |delete_me|
params.delete(delete_me)
end
params
end
end
ApiController
class Api::ApiController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource
rescue_from CanCan::AccessDenied do |exception|
return render :status => 401, :json => {:success => false, :errors => [exception.message]}
end
end
Result of calling the delete action in the test:
delete :destroy, {:user_id => #user, :id => #payment_method.id}
#<ActionController::TestResponse:0x007fb999cf0080
#blank=false,
#block=nil,
#body=
["{\"success\":false,\"errors\":[\"You are not authorized to access this page.\"]}"],
#cache_control={},
#charset="utf-8",
#content_type=application/json,
#etag=nil,
#header={"Content-Type"=>"application/json; charset=utf-8"},
#length=0,
#request=
The other actions seem to work but for Update and Destroy, I keep getting that AccessDenied error. Any idea what I could be doing wrong?
Your ApiController appears to be namespaced, you'll need to change the before_filter to the following:
before_filter :authenticate_api_user!
Then, you need to adjust Cancan to use the current_api_user instead of current_user:
def current_ability
#current_ability ||= ::Ability.new(current_api_user)
end
These links will help:
http://rubydoc.info/github/plataformatec/devise/master/Devise/Controllers/Helpers
https://github.com/ryanb/cancan/issues/656
http://mikepackdev.com/blog_posts/12-managing-devise-s-current-user-current-admin-and-current-troll-with-cancan
I'm trying to use my Users controller to notify the user when their email has already been used in a registration, but even when the email already exists, I still get the error "Plase validate your input and try again," rather than "You've already registered! Thanks for being enthusiastic!" Is using the controller not the create way of achieving this behavior?
In the rails console (assuming "foo#bar.com" is in the database"), when I use user = User.new(name:"Example", email:"foo#bar.com") then User.find_by_email(user.email) it does return the proper User entry, so I'm not sure if I'm on the right track and just executing it incorrectly or what. Any ideas?
users_controller.rb:
class UsersController < ApplicationController
def new
#user = User.new(params[:user])
end
def create
#user = User.new(params[:user])
if #user.save
flash[:success] = "Thanks for supporting cofind! We'll be in touch!"
redirect_to root_path
UserMailer.welcome_email(#user).deliver
else
if #user.email == User.find_by_email(#user.email)
flash[:error] = "You've already registered! Thanks for being enthusiastic!"
redirect_to root_path
else
flash[:error] = "Plase validate your input and try again."
redirect_to signup_path
end
end
end
end
user.rb:
class User < ActiveRecord::Base
attr_accessible :email, :name
before_save { |user| user.email = email.downcase }
validates :name, presence: true
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
end
this line
if #user.email == User.find_by_email(#user.email)
checks the user's email (a string) against a user record (an ActiveRecord object) which will always be false. You should change that to
if User.where(email: #user.email).exists?
User has two addresses shipping(:address_type=0) and billing(:address_type=1)
User form with 2 classic nested forms for each address type are generated square times every submit and failed validation.
Models:
class User < ActiveRecord::Base
has_many :addresses, :dependent => :destroy
accepts_nested_attributes_for :addresses
validates_associated :addresses
end
class Address < ActiveRecord::Base
belongs_to :user
validates :user, :address_type, :first_name, :last_name, :street
end
Controller
class UsersController < ApplicationController
public
def new
#user = User.new
#shipping_address = #user.addresses.build({:address_type => 0})
#billing_address = #user.addresses.build({:address_type => 1})
end
def create
#user = User.new(params[:user])
if #user.save
#fine
else
render => :new
end
end
Uncomplete Form
=form_for #user, :html => { :multipart => true } do |ff|
=ff.fields_for :addresses, #shipping_address do |f|
=f.hidden_field :address_type, :value => 0
=ff.fields_for :addresses, #billing_address do |f|
=f.hidden_field :address_type, :value => 1
=ff.submit
The form should look like this:
=form_for #user, :html => { :multipart => true } do |ff|
=ff.fields_for :addresses do |f|
Nothing else.
Addressess is already a collection, so you should have just one rendering of it.
Also that ":addresses, #shipping_address" makes it to render addresses AND shipping address, even if it's included in #user.addresses.
The addressess built in new action will show there because they are in the addresses collection.
EDIT:
If you need only these two addresses, you can sort it and pass it to fields_for directly:
=form_for #user, :html => { :multipart => true } do |ff|
=ff.fields_for ff.object.addresses.sort{|a,b| a.address_type <=> b.address_type } do |f|
That should do it.
Surprised? I guess not but I was. I found it am I correct? And its stupid and simple.
There is no #shipping_address nor #billing_address when validation fails and rendering the new action (the form) again. But #user has already 2 addresses builded and nested form behave correctly to render each twice for first time failed validation.
def create
#user = User.new(params[:user])
if #user.save
#fine
else
#user.addresses.clear
#user_address = #user.addresses.build({:address_type => 0})
#user_address.attributes = params[:user][:addresses_attributes]["0"]
#billing_address = #user.addresses.build({:address_type => 1})
#billing_address.attributes = params[:user][:addresses_attributes]["1"]
render => :new
end
end
I have the following in my model:
validates :name, :if => :should_validate_name?,
:presence => {:message => "Enter your name"},
:length => { :maximum => 50 },
:allow_blank => true
def should_validate_name?
validating_name || new_record?
end
In my controller I have the following:
def create
#user = User.new(params[:user])
#user.validating_name = false
if #user.save
else
render :action => 'new'
end
end
I don't want to validate for the presence of a name at this point and wish to turn it off.
I thought the code above would work but it doesn't. I don't know why.
You're in the create action, creating a new record. So new_record? will be true, even if validating_name isn't.