Rails - undefined method `authenticate' - ruby

I am receiving following error while trying to authenticate a user.
NoMethodError (undefined methodauthenticate' for #)`
user.authenticate('password') is successful(i.e returns the user object) when I execute the command from rails console.
irb(main):008:0> user.authenticate("sanket")
=> #<User id: 2, name: "Sanket", email: "sanket.meghani#infibeam.net", created_at: "2014-02-14 08:58:28", updated_at: "2014-02-14 08:58:28", password_digest: "$2a$10$KNuBgvqVDIErf3a24lMcaeNt1Hyg0I8oreIQSEYsXY4T...", remember_token: "3b64273a4fcced7c8bf91f7f7490e60a5919658d">
However when I put user.authenticate in a helper class, and access it using a url, it says
undefined method 'authenticate' for #<ActiveRecord::Relation:0x007fd9506dce38>
I am following Rails Tutorial
My user model looks like:
class User < ActiveRecord::Base
attr_accessible :email, :name, :password, :password_confirmation
has_secure_password
.
.
.
end
Related method in session_helper.rb looks like:
def create
user = User.where(:email => params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_to user
else
flash.now[:error] = 'Invalid email/password combination'
render "new"
end
end
It gives above error on if user && user.authenticate(params[:session][:password]) line.
What surprises me is, it is working from rails console, however the same call is not working from rails server.

As you can see in your error, where returns a relation, not a single object.
Check the related question: Why does a single record lookup return an array? (Rails beginner)
In your case, you can add first to the end of method chain, so it will return the first element of this relation:
user = User.where(:email => params[:session][:email].downcase).first

Related

Sinatra initialize a namespace controller

Under the commands folder, I'd like to initialize a controller
but Sinatra reports this error in the logs
ArgumentError: wrong number of arguments (given 1, expected 2)
/home/daniel/sinatraApi/app/commands/authenticate_user.rb:6:in `initialize'
/home/daniel/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/builder.rb:86:in `new'
2.0.7/lib/rack/builder.rb:147:in `to_app'
config.ru:15:in `inner_app'
/
The controllers are called
use AuthenticateUser
run ApplicationController
I've tried to add
use Commands::AuthenticateUser
or require
require "./app/commands/authenticate_user"
on config.ru
Authenticate_user
require 'jwt'
#require './app/controllers/application'
class AuthenticateUser
prepend SimpleCommand
def initialize(email, password)
#email = email
#password = password
end
def call
JsonWebToken.encode(user_id: user.id) if user
end
private
attr_accessor :email, :password
def user
user = User.find_by_email(email)
return user if user && user.authenticate(password)
errors.add :user_authentication, 'invalid credentials'
nil
end
end
How can I setup the namespace or nested controllers in Sinatra?

FactoryGirl and associations validation

I have the following factory setup
FactoryGirl.define do
factory :image do
title 'Test Title'
description 'Test Description'
photo File.new("#{Rails.root}/spec/fixtures/louvre_under_2mb.jpg")
after(:build) do
FactoryGirl.build_list(:category, 1)
end
end
end
Within my model i have these validations
class Image < ActiveRecord::Base
has_many :categories
validates :title, presence: { message: "Don't forget to add a title" }
validates :description, presence: { message: "Don't forget to add a description" }
validates :categories, presence: { message: 'Choose At Least 1 Category' }
end
When I run this test it fails
RSpec.describe Image, type: :model do
it 'should have a valid Factory' do
expect(FactoryGirl.build(:image)).to be_valid
end
end
Failure/Error: expect(FactoryGirl.build(:image)).to be_valid
expected #<Image id: nil, title: "Test Title", description: "Test Description", photo_file_name: "louvre_under_2mb.jpg", photo_content_type: "image/jpeg", photo_file_size: 65618, photo_updated_at: "2015-12-15 08:01:07", created_at: nil, updated_at: nil> to be valid, but got errors: Categories Choose At Least 1 Category
Am i approaching this wrong as i was thinking that the validations would not kick in until the whole object was created? or am i thinking about this incorrectly ?
Thanks
the problem is in this part.
after(:build) do
FactoryGirl.build_list(:category, 1)
end
this will create a list of categories of size 1, but those categories are not associated to the image object. The proper way is as follows:
transient do
categories_count 1
end
after(:build) do |image, evaluator|
image.categories = build_list(:category, evaluator.categories_count)
end
or
transient do
categories_count 1
end
categories { build_list(:category, categories_count) }
personally, I would choose this last option.
the photo attribute as well is problematique. FactoryGirl is all about flexibility of creating records. But the way you're using it will not present any flexibility, so the photo attribute will be shared between all the records that you'll create using this factory. And sooner or later you'll face some headaches.
so the proper way of creating the photo attribute is as follows.
transient do
photo_name 'default_photo.jpg'
end
photo { File.new(File.join(Rail.root, "spec/fixtures", photo_name) }
than you can use it this way
FactoryGirl.build(:image, photo_name: 'new_photo_name.jpg')
I would recommend don't use after method in image factory. You should create a correct association. Using this you'll resolve validation error and will't have others problems in the future.
class Image
accepts_nested_attributes_for :categories
end
FactoryGirl.define do
factory :image do
categories_attributes { [FactoryGirl.attributes_for(:category)] }
end
end

Validation error in test but error array is empty

I have this code for creating a topic and post in a forum application in Rails 3.1:
def create
#topic = Topic.new(:name => params[:topic][:name], :last_post_at => Time.now)
#topic.forum_id = params[:topic][:forum_id]
#topic.user = current_user
if #topic.save
#post = Post.new(:content => params[:post][:content])
#post.topic = #topic
#post.user = current_user
#post.save!
...
When posting to the create method via the corresponding form, the topic and the post are created and both save calls are successful.
When I call the create method via a functional test, the topic is saved but the post has validation errors.
ActiveRecord::RecordInvalid: Validation failed:
app/controllers/topics_controller.rb:23:in `create'
test/functional/topics_controller_test.rb:26:in `block in <class:TopicsControllerTest>'
The test looks like this:
test "should create topic" do
post :create, :topic => {:name => "New topic", :forum_id => forums(:one).id}, :post => {:content => "Post content"}
end
(current_user is logged in via a setup method.)
When I display the errors of the post object via the debugger or with #post.errors.full_messages, the error array is empty.
The Post model looks like this:
class Post < ActiveRecord::Base
attr_accessible :content
belongs_to :topic
belongs_to :user
end
And the Topic model:
class Topic < ActiveRecord::Base
belongs_to :user
belongs_to :last_poster, class_name: 'User'
attr_accessible :name, :last_poster_id, :last_post_at
belongs_to :forum
has_many :posts, :dependent => :destroy
end
How can I find out what is causing the validation error?
The problem was that I used mocha's Post.any_instance.stubs(:valid?).returns(false) in a test that was executed before my failing test.
Apparently, you have to restore the original behavior before proceeding with other tests by calling Post.any_instance.unstub(:valid?).

Issues with Carrierwave in Rails 3.1.0

I'm trying to attach a file "attachment" to my upload model. The attachment field in my db after creation is nil, and links link #upload.attachment.url just redirect to a parent object. Maybe I'm doing something wrong? I haven't used Carrierwave before.
# Model
require 'carrierwave/orm/activerecord'
class Upload < ActiveRecord::Base
mount_uploader :attachment, AttachmentUploader
end
Went with the basics for for the attachment field
# Form
= form_for #upload, :html => { :multipart => true } do |f|
%br
= f.file_field :attachment
And more basics with the controller:
def create
#upload = Upload.new(params[:upload])
#upload.attachment = params[:file]
if #upload.save
redirect_to #upload
end
end
I'm not getting any errors in my console, but the :attachment string on the student model is always nil.
Thanks!
Why u have added the line
#upload.attachment = params[:file]
remove it. it will work. attachment string is null because there is not params file in the form.

Rails/Mongoid error messages in nested attributes

I have a contact info class defined like this:
class ContactInfo
include Mongoid::Document
validates_presence_of :name, :message => ' cannot be blank'
field :name, :type => String
field :address, :type => String
field :city, :type => String
field :state, :type => String
field :zip, :type => String
field :country, :type => String
embedded_in :user
end
This contact info class is embedd as a nested attribute inside my user class:
class PortalUser
include Mongoid::Document
accepts_nested_attributes_for :contact_info
end
When I attempt to save a user without a name, I get an error message like this:
Contact info is invalid
However, this is not very useful to the end user, because he or she doesn't know what contact info is invalid. The REAL message should be 'Name cannot be blank'. However, this error is not being propagated upwards. Is there a way to get the 'Name cannot be blank' message inside the user.errors instead of the 'Contact info is invalid' error message?
Thanks
Here's the solution I eventually came up with:
Added these lines to the user class
after_validation :handle_post_validation
def handle_post_validation
if not self.errors[:contact_info].nil?
self.contact_info.errors.each{ |attr,msg| self.errors.add(attr, msg)}
self.errors.delete(:contact_info)
end
end
Instead of returning the user.errors.full_messages create a specific error message method for your user model where you handle all your embedded document errors.
class PortalUser
include Mongoid::Document
accepts_nested_attributes_for :contact_info
def associated_errors
contact_info.errors.full_messages unless contact_infos.errors.empty?
end
end
and in your controller
flash[:error] = user.associated_errors
My solution that covers each embedded document validation error is the following:
after_validation :handle_post_validation
def handle_post_validation
sub_errors = ActiveModel::Errors.new(self)
errors.each do |e|
public_send(e).errors.each { |attr,msg| sub_errors.add(attr, msg)}
end
errors.merge!(sub_errors)
end
There might be a solution in the controller...
in the create action you can add something like
params[:portal_user][:contact_info_attributes] = {} if params[:portal_user] && params[:portal_user][:contact_info_attributes].nil?
This will force contact_info creation, and will trigger an error on the right field
If you don't add this, contact_info is not created

Resources