Rails 3 - wrong number of arguments (0 for 1) - ruby-on-rails-3

I'm trying to build an authentication system for my application
to register the user fills in a form which then submitted calls user#signup
def signup
#user = User.new(params[:user])
#user.password(params[:user][:password])
#user.save
end`
My user model contains
def password(pass)
#password=pass
self.salt = User.random_string(10)
self.hashed_password = User.encrypt(#password, self.salt)
end
When trying to debug, I checked what is contained in my #user hash:
After #user = User.new(params[:user]) the hash contains my parameter exept 'id', 'hashed_password' and 'salt' (plus the timestamps) which are empty
After #user.password(params[:user][:password]) the hash now contains values for 'hashed_password' and 'salt'
#user.save returns
ArgumentError in UsersController#signup
wrong number of arguments (0 for 1)
Stack trace
Started POST "/users/signup" for 127.0.0.1 at Fri Oct 05 14:23:49 +1000 2012
Processing by UsersController#signup as HTML
Parameters: {"user"=>{"last_name"=>"last", "first_name"=>"first", "login"=>"myusername", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "email"=>"me#gmail.com", "dob(1i)"=>"1980", "dob(2i)"=>"4", "dob(3i)"=>"2"}, "authenticity_token"=>"R8/BNPox9F9rkUXZQ84xjnsplRjqLJYe35EtGjKEAWk=", "utf8"=>"✓", "commit"=>"Create User"}
(0.1ms) begin transaction
(0.0ms) rollback transaction
Completed 500 Internal Server Error in 10ms
ArgumentError (wrong number of arguments (0 for 1)):
app/controllers/users_controller.rb:17:in `signup'
app/controllers/users_controller.rb:16:in `signup'
Rendered /Library/Ruby/Gems/1.8/gems/actionpack-3.2.8/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.1ms)
Rendered /Library/Ruby/Gems/1.8/gems/actionpack-3.2.8/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.1ms)
Rendered /Library/Ruby/Gems/1.8/gems/actionpack-3.2.8/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (7.8ms)
Any idea?

I'm guessing you have a column called password and/or you have a validation referencing :password.
In that case, the problem is that you've overridden password -- the implicit zero-parameter getter -- with password(pass), a one-parameter setter. You should instead move your setter to password=, and make a getter that always returns nil:
def password
nil
end
def password=(pass)
#password = pass
self.salt = User.random_string(10)
self.hashed_password = User.encrypt(#password, self.salt)
end
As a bonus, this means you can eliminate the explicit password-setting call, since User.new(:password => 'xyz') will call password= automatically.

Related

Devise async with Mandrill mailer wrong number of arguments (1 for 2)

I'm using delayed_job to handle background jobs. I recently came across the devse_async gem to integrated delayed_job and devise.
I am receiving a wrong number of arguments (1 for 2) error when delayed_job processes the email job in the queue. I should note I'm using Mandrill's API to send these emails.
delayed job console
Starting job worker
[Worker(host:MacBook-Pro.local pid:21007)] Job Devise::Async::Backend::DelayedJob#perform (id=1) RUNNING
[Worker(host:MacBook-Pro.local pid:21007)] Job Devise::Async::Backend::DelayedJob#perform (id=1) FAILED (0 prior attempts) with ArgumentError: wrong number of arguments (1 for 2)
[Worker(host:MacBook-Pro.local pid:21007)] 1 jobs processed at 30.3564 j/s, 1 failed
trace
wrong number of arguments (1 for 2)
/Users/Sites/app/mailers/devise_mailer.rb:6:in `confirmation_instructions'
devise_mailer
class DeviseMailer < MandrillMailer::TemplateMailer
include Devise::Controllers::UrlHelpers
include Devise::Mailers::Helpers
default from: 'no-reply#foobar.com'
def confirmation_instructions(record, token)
#resource = record
# Route mailer to send the proper subject and template
if #resource.pending_reconfirmation?
confirmation_template = 'Reconfirmation Instructions'
confirmation_subject = 'Confirm your new email'
else
confirmation_template = 'Confirmation Instructions'
confirmation_subject = 'Confirmation Email'
end
# Include proper greeting in email based on User type
recipient_name = nil
if #resource.type == "Business"
recipient_name = record.business_name
else
recipient_name = record.first_name
end
puts "sending confirmation email"
host = ActionMailer::Base.default_url_options[:host]
mandrill_mail template: confirmation_template,
subject: confirmation_subject,
from_name: 'foobar',
to: { email: 'contact#foobar.ca' },
vars: {
'FNAME' => recipient_name,
'LIST_COMPANY' => "foobar",
'HTML_LIST_ADDRESS_HTML' => "foobar",
'CONFIRMATION_LINK' => "%s/users/confirmation?confirmation_token=#{record.confirmation_token}" % ENV['MAIL_HOST']
# "http://0.0.0.0:3000/users/confirmation?confirmation_token=#{record.confirmation_token}"
},
async: true
end
end
registrations_controller.rb
def new
build_resource({})
resource.build_supp_form
respond_with self.resource
end
def create
super
end
The use of database encrypted tokens was introduced in devise 3.1 (https://github.com/plataformatec/devise/blob/master/CHANGELOG.md#310---2013-09-05), so your confirmation_instructions mailer method doesn't expect any token as the second parameter.
In fact you're not using that parameter anywhere in your method, notice you call record.confirmation_token.
Just remove the second parameter in the method signature and you should be good to go:
def confirmation_instructions(record)
...
end

create a (Prawn) PDF inside custom DelayedJob and upload it to S3?

Using: Rails 4.2, Prawn, Paperclip, DelayedJobs via ActiveJobs, Heroku.
I have a PDF that is very large and needs to be handled in the background. Inside a custom Job I want to create it, upload it to S3, and then email the user with a url when its ready. I facilitate this via a PdfUpload model.
Is there anything wrong with my approach/code? Im using File.open() as outlined in examples I found, but this seems to be the root of my error ( TypeError: no implicit conversion of FlightsWithGradesReport into String ).
class PdfUpload < ActiveRecord::Base
has_attached_file :report,
path: "schools/:school/pdf_reports/:id_:style.:extension"
end
/pages_controller.rb
def flights_with_grades_report
flash[:success] = "The report you requested is being generated. An email will be sent to '#{ current_user.email }' when it is ready."
GenerateFlightsWithGradesReportJob.perform_later(current_user.id, #rating.id)
redirect_to :back
authorize #rating, :reports?
end
/ the job
class GenerateFlightsWithGradesReportJob < ActiveJob::Base
queue_as :generate_pdf
def perform(recipient_user_id, rating_id)
rating = Rating.find(rating_id)
pdf = FlightsWithGradesReport.new( rating.id )
pdf_upload = PdfUpload.new
pdf_upload.report = File.open( pdf )
pdf_upload.report_processing = true
pdf_upload.report_file_name = "report.pdf"
pdf_upload.report_content_type = "application/pdf"
pdf_upload.save!
PdfMailer.pdf_ready(recipient_user_id, pdf_upload.id)
end
end
This results in an error:
TypeError: no implicit conversion of FlightsWithGradesReport into String
Changing this:
pdf_upload.report = File.open( pdf )
to this:
pdf_upload.report = StringIO.new(pdf.render)
fixed my problem.

Loading ISSUE in rails

I'm facing a problem with Loading a Constant in Rails console (rails console). Here how my structure look like this
- app
- controllers
- models
- earning
- daily_earning.rb
- monthly_earning.rb
- weekly_earning.rb
- yearly_earning.rb
- views
Some more information
I also have a rake which look like this
namespace :past_days do
desc "Past 7 Days Earning"
task :earning => :environment do
puts $:.select { |i| i=~ /models/ }.to_yaml
7.downto(1).each do |i|
start_date = i.days.ago.beginning_of_day
puts "====== Dumping past #{start_date.strftime('%A')} earning ====="
end_date = start_date.end_of_day
Performer.top_daily_earners(start_date,end_date)
puts "====== Dumped #{start_date.strftime('%A')} earning !!! ======="
puts
end
end
end
And the top_daily_earners method look like this If you check this #klass = DailyEarning
def top_daily_earners(start_date=nil,end_date=nil)
unless start_date or end_date
date = 1.day.ago
#start_date,#end_date = date.beginning_of_day,date.end_of_day
end
if start_date and end_date
#start_date,#end_date = start_date,end_date
end
#klass = DailyEarning
#earning_performers = retrieve_earnings
puts "COUNT -----"
puts #earning_performers.count
puts ""
store_earning
end
Question :
Now when I run rake task bundle exec rake past_days:earning (Rake run without any error) all work fine but when I run this
rails console see attach screenshot
I get errors NameError: uninitialized constant DailyEarning and I have manually require the file as can be seen the above screenshot
So the POINT of all the above question is why the error on rails console (NameError: uninitialized constant DailyEarning) and why not the error in
rake task
Attaching DailyEarning Code based on #dtt comment
puts 'DailyEarning'
class DailyEarning
include Mongoid::Document
store_in session: "writeable"
field :performer_id, :type => Integer
field :user_id,:type => Integer
field :stage_name,:type => String
field :full_name,:type => String
field :start_date,:type => DateTime
field :end_date,:type => DateTime
field :amount,:type => BigDecimal
before_create :other_details
## Please avoid using default scope because it AFAIK it make the date parameter as static
class << self
def default_scoping
where(:start_date.gte => 1.day.ago.beginning_of_day).and(:end_date.lte => 1.day.ago.end_of_day)
end
end
private
def other_details
## Fetch from Mongo Instead of Mysql to avoid the slow sql query
performer_source = PerformerSource.where(performer_id: performer_id).only([:stage_name,:user_id]).first
self.user_id = performer_source.user_id
self.stage_name = self.stage_name
#self.full_name = self.full_name
end
end
My understanding is that to autoload a model in a folder you would need to namespace it:
to autoload the model in app/models/earning/daily_earning.rb
class Earning::DailyEarning
end
it may be that instead you could use:
module Earning
class DailyEarning
end
end

How to handle exceptions caused by nil:NilClass

I have a model called quiz, which has many questions models. I want to add some kind of esception handling so that when the user types in a wrong quiz_id in the URL, an error page would be rendered.
I wrote some helper methods in my QuestionsController to handle the exceptions:
private
def render_error(message)
#error_message = message
render 'error'
end
def active_quizzes_safe
active_quizzes = Quiz.active_quizzes(current_user.id)
render_error('Sorry! The request is invalid! Please log in again!') if active_quizzes.nil?
active_quizzes
end
def active_quiz_safe(quiz_id)
active_quiz = active_quizzes_safe.where(id: quiz_id).first
render_error('The quiz does not exist or you are not allowed to take this quiz!') if active_quiz.blank?
active_quiz
end
And here is the action in QuestionsController which has problems:
def show_quiz
if current_user
#quiz = active_quiz_safe(params[:quiz_id])
#questions = #quiz.questions
end
end
So if the :quiz_id in the URL localhost:3000/MY_URL/:quiz_id is not correct(that is, a record cannot be found), an error page should be rendered by the render_error mothod. However, when I tired a wrong :quiz_id, I got undefined method 'questions' for nil:NilClass. I guess this is because of the #questions = #quiz.questions in show_quiz method.
However, is the execution supposed to halt after the render_error action, which is before #questions = #quiz.questions? Why #questions = #quiz.questions is executed anyway?
In addtion, are there any standard ways to handle nil:NilClass errors like this?
Thank you!!
Look in your public/404.html, public/422.html and public/500.html files. Rails will automatically redirects if error occurs anyway. So I think you don't need to manually handle exceptions, except you have specific case. To test and view this error pages run application in production bundle exec rails s RAILS_ENV=production.
Calling render method does not halt the action. So you should carefully design your action to ensure that you return immediately after rendering. Like this:
def show_quiz
if current_user
active_quizzes = Quiz.active_quizzes(current_user.id)
if active_quizzes.nil?
render_error('Sorry! The request is invalid! Please log in again!')
else
#quiz = active_quizzes_safe.where(id: quiz_id).first
if #quiz.blank?
render_error('The quiz does not exist or you are not allowed to take this quiz!')
else
#questions = #quiz.questions
end
end
end
end
But in this case, I think it's better to use some exception control, like this:
def show_quiz
if current_user
active_quizzes = Quiz.active_quizzes(current_user.id)
#quiz = active_quizzes_safe.find(quiz_id)
#questions = #quiz.questions
end
rescue ActiveRecord::RecordNotFound
render_error 'The quiz does not exist or you are not allowed to take this quiz!'
end

Carrierwave: set image path and skip the upload

I would like to set some images without uploading. (They already exist, or another task saves them...)
If I try (in rails console):
user = User.last
user.picture = '/some/picture.jpg'
user.save
user.picture # nil
The only way to do that is to set remote_picture_url, and then delete the upload (which is stupid)
Is there any method in carrierwave that lets you modify only the filename ?
class User < ActiveRecord::Base
attr_accessible :picture
# Don't want to write to the database, but want to be able to check
attr_writer :skip
# set a default value
def skip
#skip ||= false
end
mount_uploader :image, PictureUploader
# Make sure that the skip callback comes after the mount_uploader
skip_callback :save, :before, :store_picture!, if: :skip_saving?
# Other callbacks which might be triggered depending on the usecase
#skip_callback :save, :before, :write_picture_identifier, id: :skip_saving?
def skip_saving?
skip
end
end
class PictureUploader < Carrierwave::Uploader::Base
# You could also implement filename=
def set_filename(name)
#filename = name
end
end
Assuming you have the setup above, in your console:
user = User.last
user.picture.set_filename('/some/picture.jpg')
user.skip = true
# Save will now skip the callback store_picture!
user.save
user.picture # /some/picture.jpg
It should be noted that if you're in the console and you update an existing record that has an attached file (ie user.picture.file) it will show the old url/location. If you quit the console (assuming you're not in sandbox mode) and come back and query the same object it will have the updated url/location.