I can't get my any test to run because every user I try to fabricate generates validation errors.
I have the following test.
class BillTest < ActiveSupport::TestCase
def setup
load_all_sponsors
#the_bill = Bill.new(:govtrack_name => "h1")
#user1 = Fabricate(:user1)
#user2 = Fabricate(:user2)
My fabrications are defined by:
Fabricator(:user) do
email 'another_user_here#domain.com'
name 'anew user'
roles_mask 1
password "secret"
password_confirmation "secret"
polco_groups {[Fabricate(:polco_group, :name => 'foreign', :type => :custom)]}
end
Fabricator(:admin, :class_name => :user) do
email 'admin#yourdomain.com'
name 'Administrator'
roles_mask 5
password "secret"
password_confirmation "secret"
end
Fabricator(:registered, :class_name => :user) do
email 'registered_user#domain.com'
name 'Tim TheRegistered'
roles_mask 2
password "the_secret"
password_confirmation "the_secret"
polco_groups {[Fabricate(:polco_group, {:name => 'AL', :type => :state}),
Fabricate(:polco_group, {:name => 'AL01', :type => :district}),
Fabricate(:polco_group, {:name => "Kirk\'s Kids" , :type => :custom})]}
end
Fabricator(:user1, :class_name => :user) do
email 'user1#domain.com'
name 'User1'
roles_mask 2
password "the_big_secret"
password_confirmation "the_big_secret"
polco_groups {[Fabricate(:polco_group, {:name => 'AL', :type => :state}),
Fabricate(:polco_group, {:name => 'AL01', :type => :district}),
Fabricate(:polco_group, {:name => "Kirk\'s Kids" , :type => :custom})]}
end
Fabricator(:user2, :class_name => :user) do
email 'user2#domain.com'
name 'User2'
roles_mask 2
password "the_big_secret"
password_confirmation "the_big_secret"
polco_groups {[Fabricate(:polco_group, {:name => 'AL', :type => :state}),
Fabricate(:polco_group, {:name => 'FL01', :type => :district}),
Fabricate(:polco_group, {:name => "Ft. Sam Washington 1st Grade" , :type => :custom})]}
end
No matter which test runs, I get the same error
9) Error:
test_update_from_directory(BillTest):
Mongoid::Errors::Validations: Validation failed - Email is already taken, Email is already taken, Name is already taken.
test/unit/bill_test.rb:8:in `setup'
I have tried a number of different fabricators, inheriting in all kinds of different ways and nothing gets past this error. I'm pretty desperate for help on this one.
You should be user the "ffaker" gem to generate email addresses and the like in your specs. Also, you should be inheriting fields form previously defined fabricators, as illustrated below.
Fabricator(:user) do
email { Faker::Internet.email }
name { Faker::Name.name }
roles_mask 1
password "secret"
password_confirmation "secret"
polco_groups {[Fabricate(:polco_group, :name => 'foreign', :type => :custom)]}
end
Fabricator(:admin, :from => :user) do
roles_mask 5
end
Fabricator(:registered, :from => :user) do
roles_mask 2
polco_groups {[Fabricate(:polco_group, :name => 'AL', :type => :state),
Fabricate(:polco_group, :name => 'AL01', :type => :district),
Fabricate(:polco_group, :name => "Kirk\'s Kids" , :type => :custom)]}
end
Fabricator(:user1, :from => :registered)
Fabricator(:user2, :from => :registered) do
polco_groups {[Fabricate(:polco_group, {:name => 'AL', :type => :state}),
Fabricate(:polco_group, {:name => 'FL01', :type => :district}),
Fabricate(:polco_group, {:name => "Ft. Sam Washington 1st Grade" , :type => :custom})]}
end
It is unrelated to your issue, but it looks like user1 and user2 should just be calls to Fabricate and not actually defined as Fabricators. I don't recommend putting that much explicit information in the Fabricator. You should only be defining was is necessary to generate a valid object. Any specific data should be in the service of a particular spec.
After running in to Machinist and Fabricator issues with Mongoid I've settled on FactoryGirl - the syntax feels like a step back - but it works.
The issues I had with the others were related to validation, STI and polymorphism.
Related
I have 2 tables User and Member and there relation is
In user
has_one :member, :class_name => 'User::Member'
Member
belongs_to :user
I am trying to insert data using console and I am using this code
u = User.create(
:group => UserGroup.find_by_slug(:members),
:first_name => 'abc',
:last_name => 'fgh',
:company_name => 'xyz',
:email => 'test#test.com',
:password => '123456',
:password_confirmation => '123456'
)
m = User::Member.create(
:user => u,
:pricing_plan => PricingPlan.order('RANDOM()').first,
:state => UserState.order('RANDOM()').first,
:industry => Industry.order('RANDOM()').first,
:fy_start_month => 7
)
It is throwing this error
syntax error, unexpected tIDENTIFIER, expecting $end
) m = User::Member.create(
I am wondering what is wrong with my syntax.Thanks in advance
This may be due to an invisible char (not whitespace). Your syntax seems to be ok, but if your editor allows you to show invisibles (in textmate, for example, go to view > show invisibles, try to do that. It sometimes happens to me that I insert invisibles instead of whitespace.
To give you an impression what I am talking about:
This is invisibles hidden
This is invisibles shown. The invisible lozenges you do not see in normal mode cause a syntax error:
I am assuming user_id is your foreign key which is associated with the users table.
If so use following
m= Member.create(
:user_id => u.id,
:pricing_plan => PricingPlan.order('RANDOM()').first,
:state => UserState.order('RANDOM()').first,
:industry => Industry.order('RANDOM()').first,
:fy_start_month => 7
)
try this
In your User Model
has_one :member
attr_accessible :member_attributes
accepts_nested_attributes_for :member
In your Member Model
belongs_to :user
then try in your console as well as your form
user = User.create(
:group => UserGroup.find_by_slug(:members),
:first_name => 'abc',
:last_name => 'fgh',
:company_name => 'xyz',
:email => 'test#test.com',
:password => '123456',
:password_confirmation => '123456'
)
and
user.build_member(
:pricing_plan => PricingPlan.order('RANDOM()').first,
:state => UserState.order('RANDOM()').first,
:industry => Industry.order('RANDOM()').first,
:fy_start_month => 7
)
or
member = Member.create(
:user_id => user.id,
:pricing_plan => PricingPlan.order('RANDOM()').first,
:state => UserState.order('RANDOM()').first,
:industry => Industry.order('RANDOM()').first,
:fy_start_month => 7
)
There is a mass assignment defined in sys_log model in our rails 3.1.4 app:
attr_accessible :log_date, :user_name, :user_id, :user_ip, :action_logged, :as => :new_log
A method is defined in application_controller to save the log:
def sys_logger(action_logged)
log = SysLog.new(:log_date => Time.now, :user_id => session[:user_id], :user_name => session[:user_name], :user_ip => session[:user_ip],
:action_logged => action_logged, :as => :new_log)
log.save
end
However, the mass assignment does not work. Here is the warning message:
WARNING: Can't mass-assign protected attributes: log_date, user_id, user_name,
user_ip, action_logged, as
:new_log is not working as defined. What's wrong with the code above? Thanks so much.
The :as => :new_log is now part of the hash of attributes, instead of a separate option you pass in.
Adding some curly braces should help:
def sys_logger(action_logged)
log = SysLog.new({:log_date => Time.now, :user_id => session[:user_id],
:user_name => session[:user_name], :user_ip => session[:user_ip],
:action_logged => action_logged }, :as => :new_log)
log.save
end
Or assigning it temporarily:
def sys_logger(action_logged)
attrs = { :log_date => Time.now, :user_id => session[:user_id],
:user_name => session[:user_name], :user_ip => session[:user_ip],
:action_logged => action_logged }
log = SysLog.new(attrs, :as => :new_log)
log.save
end
I'm new to using RSpec and FactoryGirl. I'm trying to add RSpec tests to an existing codebase.
I have the following factories defined:
Factory.sequence :email do |n|
"somebody#{n}#example.com"
end
Factory.sequence :login do |n|
"inquire#{n}"
end
Factory.define :user do |f|
f.login { Factory.next(:login) }
f.email { Factory.next(:email) }
f.password 'inquire_pass'
f.password_confirmation 'inquire_pass'
f.first_name 'test'
f.last_name 'guy'
f.newsletter true
f.notify_of_events true
f.terms_of_service true
end
Factory.define :project do |project|
project.title "Example Project Title"
project.association :user
project.association :provider
project.association :project_request
project.association :offering
project.association :offering_type
end
When I try to create a Project factory in my tests, however and assign it to #project:
require 'spec_helper'
describe Charge do
before(:each) do
#provider_user = Factory(:user)
#provider = stub_model(Provider, :user => #provider_user)
#user = Factory(:user)
#project_request = stub_model(ProjectRequest)
#project = Factory(:project, :user => #user, :provider => #provider, :offering_fixed_fee_number => 700,
:project_request_id => #project_request.id)
#attr = {
:user_id => #user.id,
:provider_id => #provider.id,
:charge_client => "0.01"
}
#charge = #project.build_charge(#attr)
end
I get an error message when running the tests indicating that the validations for the associated user have failed:
Validation failed: User email can't be blank, User email is too short (minimum is 3 characters), User email does not look like a valid email address., Login can't be blank
The relevant validations on the User model are:
validates_presence_of :login, :email
validates_uniqueness_of :login, :email, :case_sensitive => false
validates_length_of :login, :within => 5..20
validates_format_of :login, :with => /^[a-z0-9-]+$/i, :message => 'may only contain letters, numbers or a hyphen.'
validates_length_of :email, :within => 3..100
validates_format_of :email, :with => Authentication.email_regex, :message => 'does not look like a valid email address.'
I'm able to create valid User factories (by themselves) with no problem. But when I try to create projects that have a User association, and specify the associated User as the factory user I created earlier, the validations on that User fail. Any ideas what I'm missing here?
Thanks very much,
Dean Richardson
Maybe it's because factory param in association method is missing:
Factory.define :project do |project|
project.association :user, :factory => :user
...
end
But in this case it could be written more easily:
Factory.define :project do |project|
project.user
...
end
See Factory Girl. Getting Started
I have the following tables in my database:
User(s) - has one profile, has many PhotoAlbums
Profile(s) - belongs to user
PhotoAlbum(s) - belongs to user, has many photos
Photo(s) - belongs to PhotoAlbum
Faker works fine when it comes to populating my users table but I now wish to update my profiles table also but it doesn't work at all. The rows in the db still remain empty. I have no errors showing up when I run rake db:populate.
Am I missing something, please help me see where I'm going wrong and help me come up with a solution as this will help me when I need to populate my other tables too. What I learn from this answer can help me with other tasks I have coming up.
libs/task/sample_data.rake
namespace :db do
desc "Create user records in the development database."
task :populate => :environment do
require 'faker'
def randomDate(params={})
years_back = params[:year_range] || 5
latest_year = params [:year_latest] || 0
year = (rand * (years_back)).ceil + (Time.now.year - latest_year - years_back)
month = (rand * 12).ceil
day = (rand * 31).ceil
series = [date = Time.local(year, month, day)]
if params[:series]
params[:series].each do |some_time_after|
series << series.last + (rand * some_time_after).ceil
end
return series
end
date
end
def decimal_selection_array(start,limit,step_size=1)
decimal_array = (start..limit).step(step_size).map{|i| i.to_s}.to_a
decimal_array.insert(0,"Below #{start.to_f}")
decimal_array.insert(-1,"Above #{limit.to_f}")
end
100.times do |n|
username = "#{Faker::Name.first_name}#{n}"
u = User.create!(
:username => username,
:email => Faker::Internet.email,
:password => "foobar"
)
u.profile.update_attributes(
:motd => Faker::Lorem.words,
#Profile details
:first_name => Faker::Name.first_name,
:last_name => Faker::Name.last_name,
:birthday => randomDate(:year_range => 60, :year_latest => 22),
:gender => (1..2).to_a.sample,
:marital_status => (1..7).to_a.sample,
:sexual_preference => (1..3).to_a.sample,
:ethnicity => (1..10).to_a.sample,
:country => Faker::Address.country,
:location => Faker::Address.country,
#About the user
:about_me => Faker::Lorem.paragraph,
#Personal stats
:height => decimal_selection_array(5.0,7.0,0.1).to_a.sample,
:body_type => (1..7).to_a.sample,
:eye_colour => (1..6).to_a.sample,
:drugs => (1..4).to_a.sample,
:alcohol => (1..4).to_a.sample,
:cigarettes => (1..3).to_a.sample,
:likes => Faker::Lorem.sentence,
:dislikes => Faker::Lorem.sentence,
:bad_habits => Faker::Lorem.sentence,
#Favourite things
:food => Faker::Lorem.sentence,
:music => Faker::Lorem.sentence,
:television => Faker::Lorem.sentence,
:book => Faker::Lorem.sentence,
:animal => Faker::Lorem.sentence,
:place => Faker::Lorem.sentence,
:possesion => Faker::Lorem.sentence
)
end
end
end
Kind regards
User profile (u.profile) does not exist when calling u.profile.update_attributes(params).
You should call u.create_profile(params) instead.
Using nested attributes could also help.
I solved this issue by:
commenting out:
before_safe :build_profile
in my User model
and my editing my rake task to look like this:
# before running this task comment out: before_create :build_profile in user.rb in order to make this work correctly
namespace :db do
desc "Create user records in the development database."
task :populate => :environment do
require 'faker'
def randomDate
"#{(1900..2012).to_a.sample}-#{(1..12).to_a.sample}-#{(1..28).to_a.sample}"
end
def decimal_selection_array(start,limit,step_size=1)
decimal_array = (start..limit).step(step_size).map{|i| i.to_s}.to_a
decimal_array.insert(0,"Below #{start.to_f}")
decimal_array.insert(-1,"Above #{limit.to_f}")
end
1000.times do |n|
username = "#{Faker::Name.first_name}#{n+1}"
User.create!(
:username => username.gsub(/[^0-9a-z]/i, ''),
:email => Faker::Internet.email,
:password => "foobar"
)
Profile.create!(
:user_id => "#{n+1}",
:motd => Faker::Lorem.sentence,
#Profile details
:first_name => Faker::Name.first_name.gsub(/[^a-z]/i, ''),
:last_name => Faker::Name.last_name.gsub(/[^a-z]/i, ''),
:birthday => randomDate,
:gender => (1..2).to_a.sample,
:marital_status => (1..7).to_a.sample,
:sexual_preference => (1..3).to_a.sample,
:ethnicity => (1..10).to_a.sample,
:country => Faker::Address.country,
:location => Faker::Address.country,
#About the user
:about_me => Faker::Lorem.paragraph,
#Personal stats
:height => decimal_selection_array(5.0,7.0,0.1).to_a.sample,
:body_type => (1..7).to_a.sample,
:hair => (1..7).to_a.sample,
:eye_colour => (1..6).to_a.sample,
:drugs => (1..4).to_a.sample,
:alcohol => (1..4).to_a.sample,
:cigarettes => (1..3).to_a.sample,
:likes => Faker::Lorem.sentence,
:dislikes => Faker::Lorem.sentence,
:bad_habits => Faker::Lorem.sentence,
#Favourite things
:food => Faker::Lorem.sentence,
:sport => Faker::Lorem.sentence,
:music => Faker::Lorem.sentence,
:television => Faker::Lorem.sentence,
:book => Faker::Lorem.sentence,
:animal => Faker::Lorem.sentence,
:place => Faker::Lorem.sentence,
:possession => Faker::Lorem.sentence
)
end
end
end
I had to make a few adjustments to what Faker was passing into my db as things were failing validation. Things like usernames with characters other than letters and numbers and this also happened with last_name too. So I had to filter all that stuff out and then I ran the take task and successfully updated my database with 1000 users with profile information.
All I have to do is uncomment the before_create any time I want to add sample data to stop profile rows being created for users on create.
I also added user_id to attr_accessible in my Profile model so that the user_id column could be populated with numbers 1 to 1000 which would match them up with a user.
How can I update all of products to assign a certain user to them?
admin = User.create(:name => "Admin", :password => "password")
walmart = Store.create(:name => 'Walmart', :address => 'San Francisco, Palo Alto')
walmartprices = walmart.products.create
([
{:name => "Rice", :price => '5.93'},
{:name => "Chicken", :price => "2.24"},
{:name => "Milk", :price => '3.81'},
{:name => 'Eggs', :price => '2.78'}
])
walmartprices.update_attribute(:user => admin)
Of course this gives me an error:
undefined method `update_attribute' for #<Array:0x5342f70>
Is this possible? How can it be done?
EDIT
These are my associations:
Product
belongs_to :user and :store
Store
has_many :products
User
has_many :products
one naive way to do this is :
walmartprices.each{|record| record.update_attribute(user: admin) }
for better performance, use update_all :
Product.where( id: walmartprices.map(&:id) ).update_all( user: admin )