Send an object using pry? - ruby

I am trying to send an object (user) to NotificationsMailer like this:
pry(main)>NotificationsMailer.welcome_facebook_user({:password=>'123',:email=>'as453now#gmail.com',:basic_profile=>{:name=>'Samir'}}).deliver
But I got this error:
ActionView::Template::Error: undefined method `basic_profile' for #<Hash:0x0000000786d588>
from /app/app/views/notifications_mailer/welcome_facebook_user.html.haml:2:in `block in _app_views_notifications_mailer_welcome_facebook_user_html_haml__4104442834642741128_62933320'
NotificationsMailer.welcome_facebook_user:
def welcome_facebook_user(user)
#user = user
puts "SENT welcome_facebook_user TO:"
puts user[:email]
mail(:to=>user[:email], :subject => "Welcome!")
end
My template:
=content_for :title do
Welcome, #{#user.basic_profile.name unless #user.basic_profile.nil?}
In the real world:
User.rb
class User < Refinery::Core::BaseModel
has_one :basic_profile
But, I want to test it using pry, how to send such a user object? why my attempt failed?

You are using hashes but you should be using objects to create object (I am assuming mass-assigment is turned off as by default) do:
basic_profile = BasicProfile.new
basic_profile.name = 'Samir'
user = User.new
user.password = '123'
user.email = 'aba#gmail.com'
user.basic_profile = basic_profile
NotificationsMailer.welcome_facebook_user(user).deliver
or turn mass-assign off and do
NotificationsMailer.welcome_facebook_user(User.new({:password=>'123',:email=>'as453now#gmail.com',:basic_profile=>BasicProfile.new({:name=>'Samir'})})).deliver

Try this
> #user = User.create!(password: "123", email: "abc#example.com")
> #user.basic_profile.name = "Samir"
> NotificationsMailer.welcome_facebook_user(#user).deliver

Related

When Running Rspec and Sinatra, I keep getting ArgumentError: wrong number of arguments (given 2, expected 0)

I've got a class method called authenticate, which works on the User class.
def self.authenticate(email:, password:)
result = DatabaseConnection.query("SELECT * FROM users WHERE email = '#{email}'")
User.new(result[0]['id'], result[0]['email'])
end
I have an Rspec test;
feature 'authentication' do
it 'a user can sign in' do
User.create(email: 'test#example.com', password: 'password123')
visit 'sessions/new'
fill_in(:email, with: 'test#example.com')
fill_in(:password, with: 'password123')
click_button 'Sign In'
expect(page).to have_content 'Welcome, test#example.com'
end
end
When running Rspec, I get the following error;
1) authentication a user can sign in
Failure/Error:
def initialize(id:, email:)
#id = id
#email = email
end
ArgumentError:
wrong number of arguments (given 2, expected 0)
# ./lib/user.rb:15:in `initialize'
# ./lib/user.rb:23:in `new'
# ./lib/user.rb:23:in `authenticate'
# ./app.rb:84:in `block in <class:BookmarkManager>'
Below is my Sinatra app;
require 'sinatra/base'
require './lib/bookmark'
require './lib/user'
require './database_connection_setup.rb'
require 'uri'
require 'sinatra/flash'
require_relative './lib/tag'
require_relative './lib/bookmark_tag'
class BookmarkManager < Sinatra::Base
enable :sessions, :method_override
register Sinatra::Flash
get '/' do
"Bookmark Manager"
end
get '/bookmarks' do
#user = User.find(session[:user_id])
#bookmarks = Bookmark.all
erb :'bookmarks/index'
end
post '/bookmarks' do
flash[:notice] = "You must submit a valid URL" unless Bookmark.create(url: params[:url], title: params[:title])
redirect '/bookmarks'
end
get '/bookmarks/new' do
erb :'bookmarks/new'
end
delete '/bookmarks/:id' do
Bookmark.delete(id: params[:id])
redirect '/bookmarks'
end
patch '/bookmarks/:id' do
Bookmark.update(id: params[:id], title: params[:title], url: params[:url])
redirect('/bookmarks')
end
get '/bookmarks/:id/edit' do
#bookmark = Bookmark.find(id: params[:id])
erb :'bookmarks/edit'
end
get '/bookmarks/:id/comments/new' do
#bookmark_id = params[:id]
erb :'comments/new'
end
post '/bookmarks/:id/comments' do
Comment.create(text: params[:comment], bookmark_id: params[:id])
redirect '/bookmarks'
end
get '/bookmarks/:id/tags/new' do
#bookmark_id = params[:id]
erb :'/tags/new'
end
post '/bookmarks:id/tags' do
tag = Tag.create(content: params[:tag])
BookmarkTag.create(bookmark_id: params[:id], tag_id: tag.id)
redirect '/bookmarks'
end
get '/users/new' do
erb :'users/new'
end
post '/users' do
user = User.create(email: params[:email], password: params[:password])
session[:user_id] = user.id
redirect '/bookmarks'
end
get '/sessions/new' do
erb :'sessions/new'
end
post '/sessions' do
user = User.authenticate(email: params[:email], password: params[:password])
if user
session[:user_id] = user.id
redirect('/bookmarks')
else
flash[:notice] = 'Please check your email or password.'
redirect('/sessions/new')
end
end
run! if app_file == $0
end
Below is the full User class
require_relative './database_connection'
require 'bcrypt'
class User
def self.create(email:, password:)
encypted_password = BCrypt::Password.create(password
)
result = DatabaseConnection.query("INSERT INTO users (email, password) VALUES('#{email}', '#{encypted_password}') RETURNING id, email;")
User.new(id: result[0]['id'], email: result[0]['email'])
end
attr_reader :id, :email
def initialize(id:, email:)
#id = id
#email = email
end
def self.authenticate(email:, password:)
result = DatabaseConnection.query("SELECT * FROM users WHERE email = '#{email}'")
User.new(result[0]['id'], result[0]['email'])
end
def self.find(id)
return nil unless id
result = DatabaseConnection.query("SELECT * FROM users WHERE id = #{id}")
User.new(
id: result[0]['id'],
email: result[0]['email'])
end
end
What I don't understand is, why is Rspec saying it was expecting 0 arguments, when the initialize method clearly requires two arguments (id, and, email)?
I need to take the id and email method from authenticate and deliver it to initialize.
I thought that's what I was doing, but both Rspec and sinatra are saying otherwise.
Thanks, in advance.
Here you are passing id as sequential args (in the authenticate method).
User.new(result[0]['id'], result[0]['email'])
However your User.new expects keyword args:
def initialize(id:, email:)
Simply pass them this way:
User.new(id: result[0]['id'], email: result[0]['email'])
Also, just something I noticed, if your DatabaseConnection.query returns no results your authenticate will raise an error from result[0]['id'] (it will say "Undefined method [] for Nil:NilClass". Maybe you should fix this and add a test case for it, for example:
def self.authenticate(email:, password:)
result = DatabaseConnection.query(
"SELECT * FROM users WHERE email = '#{email}'"
)
record = result[0]
if record
User.new(id: result[0]['id'], email: result[0]['email'])
end
end
This way the method will return nil if there's no matching user, and your if user inside post '/sessions' will work properly.

active record with ruby (not rails)

I am using active record with ruby (but not rails). I am using sqlite3 which has a test.db on file (not just in-memory). When I run the following code snippet using user.create, it complains about argument error (and when I use use.save, it throws an active record exception. Any idea what I might be doing wrong? Thanks
require 'rubygems'
gem 'activerecord'
require 'sqlite3'
require 'active_record'
ActiveRecord::Base.logger = Logger.new(STDERR)
#ActiveRecord::Base.colorize_logging = false
ActiveRecord::Base.establish_connection(
:adapter => 'sqlite3',
:host => "localhost",
:database => 'test.db'
)
class User < ActiveRecord::Base
#attr_accessible :email, :full_name
attr_accessor :email
attr_accessor :full_name
validates :email, presence: true, uniqueness: true
def initialize(email, full_name)
#email = email
#full_name = full_name
end
end
puts "full_name for user:"
full_name = gets.chomp
puts "email address:"
email = gets.chomp
user = User.new(email, full_name)
#user.save
user = User.create!(email: '', full_name: '')
Exception in first case (with User.create!):
main.rb:42:in `initialize': wrong number of arguments (1 for 2) (ArgumentError)
from /var/lib/gems/1.9.1/gems/activerecord-4.2.4/lib/active_record/inheritance.rb:61:in `new'
from /var/lib/gems/1.9.1/gems/activerecord-4.2.4/lib/active_record/inheritance.rb:61:in `new'
from /var/lib/gems/1.9.1/gems/activerecord-4.2.4/lib/active_record/persistence.rb:50:in `create!'
from main.rb:55:in `<main>'
It is complaining about the new method. According to the documentation: (http://api.rubyonrails.org/classes/ActiveRecord/Base.html), you don't need the initialize, because when you inherit from ActiveRecord::Base, you need to initialize your objects with a hash.
user = User.new({email: email, full_name: full_name})
# or
user = User.new(email: email, full_name: full_name)
# then
user.save
You need to drop the initialize and the attr_accessor from your code.
Try to comment User#initialize method and create new user like this:
User.create! email: 'halk#mail.com', full_name: 'Halk'
Explanation
When you declare AR model by heritage from ActiveRecord::Base class you don't need to define your own #initialize method. But you do. When you call User::create! method, you pass only one argument - Hash with two pairs (with email and full_name keys). But User#initialize define two parameters - email and full_name separately. So Ruby exception raise and talk about it:
wrong number of arguments (1 for 2) (ArgumentError)

Passing in an existing variable into a Ruby method

I'm trying to write a test to make sure existing users can't register (Using Cucumber, Watir-Webdriver and Page Objects)
I have the following code:
text_field(:email, :id => "user_email")
text_field(:password, :id => "user_password")
text_field(:password_confirmation, :id => "user_password_confirmation")
checkbox(:terms_privacy, :id => "user_accepts_terms")
button(:sign_up_button, :text => "Sign Up")
def unique_username
#username = "qa_automation"+"#{rand(6 ** 6)}"+"#gmail.com"
end
def sign_up
unique_username
self.email = #username
self.password = USERS['PASSWORD']
self.password_confirmation = USERS['PASSWORD']
self.check_terms_privacy
self.sign_up_button
puts "username: #{#username}"
#existing = #username
end
def sign_up_with_existing_account
puts "exisiting username: #{#existing}"
self.email = #exisiting
self.password = USERS['PASSWORD']
self.password_confirmation = USERS['PASSWORD']
self.check_terms_privacy
self.sign_up_button
puts "username: #{#existing}"
end
But the #existing variable is returning nothing. These two lines are giving me back nothing:
puts "exisiting username: #{#existing}"
self.email = #exisiting
So I guess I'm trying to figure out how to pass the #existing variable from the 'sign_up' method to the 'sign_up_with_existing_account' method? Thoughts?
You can't and should not want to do that. Testing would be a tangled mess if running one test could affect the result of another. You should set up the existing user ahead of time (using e.g. Before) so that any test that needs an existing user can take advantage of it.

Ruby JSON issue

I know the title is a bit vague, but I dont know what to put on there.
I'm developing an API with Sinatra for our backend in Ruby. The thing is that I need to be able to pass JSON to the service representing a User. The problem I'm facing is that when I run my tests it does not work, but doing it manually against the service it does work. I'm guessing there is an issue with the JSON format.
I've updated my User model to rely on the helpers from ActiveModel for the JSON serialization. I was running in too much problems with manual conversions. This is what the base User model looks like:
class User
include ActiveModel::Serializers::JSON
attr_accessor :login, :email, :birthday, :created_at, :updated_at, :password_sha, :password_salt
# Creates a new instance of the class using the information stored
# in the hash. If data is missing then nill will be assigned to the
# corresponding property.
def initialize(params = {})
return if params.nil?
self.login = params[:login] if params.key?("login")
self.email = params[:email] if params.key?("email")
self.birthday = Time.parse(params[:birthday]) rescue Time.now
if params.key?("password_salt") && params.key?("password_sha")
self.password_salt = params["password_salt"]
self.password_sha = params["password_sha"]
elsif params.key?("password")
self.set_password(params[:password])
end
self.created_at = Time.now
end
def attributes
{:login => self.login, :email => self.email, :birthday => self.birthday, :created_at => self.created_at, :updated_at => self.updated_at, :password_sha => self.password_sha, :password_salt => self.password_salt}
end
def attributes=(params = {})
self.login = params['login']
self.email = params['email']
self.birthday = params['birthday']
self.created_at = params['created_at']
self.updated_at = params['updated_at']
self.password_sha = params['password_sha']
self.password_salt = params['password_salt']
end
end
I'm using Cucumber, Rack::Test and Capybara to test my API implementation.
The code of the API application looks like this:
# This action will respond to POST request on the /users URI,
# and is responsible for creating a User in the various systems.
post '/users' do
begin
user = User.new.from_json(request.body.read)
201
rescue
400
end
end
In the above piece I expect the json representation in the request body. For some reason the params hash is empty here, don't know why
The test section that makes the actuall post looks like this:
When /^I send a POST request to "([^\"]*)" with the following:$/ do |path, body|
post path, User.new(body.hashes.first).to_json, "CONTENT_TYPE" => "application/json"
end
The example output JSON string generated by the User.rb file looks like this:
"{"user":{"birthday":"1985-02-14T00:00:00+01:00","created_at":"2012-03-23T12:54:11+01:00","email":"arne.de.herdt#gmail.com","login":"airslash","password_salt":"x9fOmBOt","password_sha":"2d3afc55aee8d97cc63b3d4c985040d35147a4a1d312e6450ebee05edcb8e037","updated_at":null}}"
The output is copied from the Rubymine IDE, but when I submit this to the application, I cannot parse it because:
The params hash is empty when using the tests
doing it manually gives me the error about needing at least 2 octets.

in UsersController#create, User.new(params[:user]) return an empty User (params looks good)

I'm kind of new to Rails 3.1. and I'm facing an issue only in my production env with my Signup form (actually, it's more about the controller).
Here is the code in User
class UsersController < ApplicationController
[...]
def create
#user = User.new(params[:user])
logger.info "value of login in param : #{params[:user][:login]}" #-> log the actual login
logger.info "value of login : #{#user.login}" #-> log empty
#user.admin = false
if #user.save
flash[:notice] = t('flash.notice.user.create.valid')
redirect_back_or_default root_path
else
flash[:notice] = t('flash.notice.user.create.invalid')
render :action => :new
end
end
end
Also, the controller logs show that the params hash is good
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"QwOqmp0CT/d4mmC1yiLT4uZjP9bNDhbUXHanCQy5ZrA=",
"user"=>{"login"=>"myLogin",
"email"=>"t.r#gmail.com",
"password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]"}}
My login form works as expected (already created users are able to sign in)
Again, this only happens in production.
EDIT: Here is my User Model
class User < ActiveRecord::Base
acts_as_authentic
#== Callbacks
before_create :set_defaults
attr_accessible :avatar ##### EDIT: TO FIX THE ISSUE, ADD THE OTHER FIELDS AS WELL
protected
def set_defaults
self.total_1 = self.total_2 = self.total_3 = 0
end
end
Just to memorialize the answer from the comments above:
Normally you can use mass assignment to set fields on a model, but when you use attr_accessible, you are then limited to only mass assigning those fields. So stuff like User.new(params[:user]) won't work; instead, you'd have to do:
#user = User.new
#user.login = params[:user][:login]
# ...etc.
#user.save
Simple add your fields to the attr_accessible list and you can go back to mass assignment.

Resources