Rails: Populate nested models with rake and forgery - ruby-on-rails

I want to populate my database with test data my user and profile models are seperate form each other with a 1-to-1 relationship. The script that I'm running creates the data but doesn't relate it together. how would I get it to related the data together?
app/models/user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :profile
attr_accessible :email, :password, :password_confirmation, :remember_me, :profile_attributes
accepts_nested_attributes_for :profile
end
app/models/profile.rb
class Profile < ActiveRecord::Base
belongs_to :user
attr_accessible :first_name, :last_name
validates :first_name, presence: true
validates :last_name, presence: true
end
lib/tasks/sample_data.rb
namespace :db do
desc "Fill database with sample data"
task populate: :environment do
User.create!(email: "dufall#iinet.net.au",
password: "123qwe",
password_confirmation: "123qwe")
Profile.create!(first_name: "Aaron",
last_name: "Dufall")
99.times do |n|
first_name = Forgery::Name.first_name
Last_name = Forgery::Name.last_name
email = "example-#{n+1}#railstutorial.org"
password = "password"
User.create!(email: email,
password: password,
password_confirmation: password)
Profile.create!(first_name: first_name,
last_name: Last_name)
end
end
end

Try to use user.create_profile! instead of Profile.create!
namespace :db do
desc "Fill database with sample data"
task populate: :environment do
user = User.create!(email: "dufall#iinet.net.au",
password: "123qwe",
password_confirmation: "123qwe")
user.create_profile!(first_name: "Aaron",
last_name: "Dufall")
99.times do |n|
first_name = Forgery::Name.first_name
Last_name = Forgery::Name.last_name
email = "example-#{n+1}#railstutorial.org"
password = "password"
user = User.create!(email: email,
password: password,
password_confirmation: password)
user.create_profile!(first_name: first_name,
last_name: Last_name)
end
end
end

Related

How to bypass validations when creating a rails object?

I have following rake task to populate my dev database with dummy data. I get an error that my weight and reps can't be blank in the make_contest block which is weird since these fields are not available in the Contest model.
I think it has to do with my "has_many :contests, through: :submissions" relation? How do I fix this?
Error
ActiveRecord::RecordInvalid: Validation failed: Reps can't be blank, Weight can't be blank
/home/christoph/Documenten/kratos/lib/tasks/populate.rake:62:in `block (2 levels) in make_contests'
/home/christoph/Documenten/kratos/lib/tasks/populate.rake:62:in `block in make_contests'
/home/christoph/Documenten/kratos/lib/tasks/populate.rake:58:in `times'
/home/christoph/Documenten/kratos/lib/tasks/populate.rake:58:in `make_contests'
/home/christoph/Documenten/kratos/lib/tasks/populate.rake:15:in `block (2 levels) in <top (required)>'
Tasks: TOP => db:pcontests
Does anybody knows what could be the reason?
rake task
def make_users
User.create!(
firstname: "Christoph",
name: "Geypen",
username: "chris88",
bio: "He is the best!",
email: "test#test.be",
password: "testtest",
password_confirmation: "testtest"
)
15.times do |n|
firstname = Faker::Name.first_name
name = Faker::Name.last_name
username = Faker::Internet.user_name
bio = Faker::Lorem.sentence
email = "example-#{n+1}#railstutorial.org"
password = "longpassword"
User.create!(
firstname: firstname,
name: name,
username: username,
bio: bio,
email: email,
password: password,
password_confirmation: password,
data_source: "rake_populate"
)
end
end
def make_contests
users = User.all.limit(5)
10.times do
name = Faker::Team.creature
description = Faker::Lorem.sentence
users.each { |user| user.contests.create!(
name: name,
description: description,
admin_id: user.id,
ctype_id: 1,
data_source: "rake_populate"
) }
end
end
def make_submissions
users = User.all.limit(15)
contests = Contest.where(data_source: "rake_populate")
contests.each do |contest|
users.each do |user|
contest.submissions.create!(
reps: rand(1..20),
weight: rand(100..350),
user_id: user.id,
contest_id: contest.id,
data_source: "rake_populate"
)
end
end
end
model validations
contest
class Contest < ActiveRecord::Base
has_many :submissions
has_many :users, through: :submissions
belongs_to :admin, class_name: 'User', foreign_key: 'admin_id'
belongs_to :ctype
validates_presence_of :name, :admin_id, :ctype_id
submission
class Submission < ActiveRecord::Base
belongs_to :user
belongs_to :contest
validates_presence_of :user_id, :reps, :weight
validates_uniqueness_of :tonnage, scope: [:user_id, :contest_id]
before_validation :calculate_tonnage
# model helpers
def calculate_tonnage
self.tonnage = self.weight * self.reps if weight && reps
end
user
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
devise :omniauthable, omniauth_providers: [:facebook]
has_many :submissions
has_many :contests, through: :submissions
has_one :contest
My create action in the controller looks as following. I am just trying to recreate this using the rake task.
def create
#contest = current_user.contests.new(contest_params)
#contest.admin_id = current_user.id
#contest.save
redirect_to contest_submissions_path(#contest)
end
I fixed it by replacing the create with new and saving afterwards. The following question is WHY does that work and create does not?
def make_contests
users = User.all.limit(5)
10.times do
name = Faker::Team.creature
description = Faker::Lorem.sentence
users.each do |user|
x = user.contests.new(
name: name,
description: description,
admin_id: user.id,
ctype_id: 1,
data_source: "rake_populate")
x.save
end
end
end
UPDATE
aannnnddd problem solved
So create instantiates the new object, validates it, and then saves it to the database. And new only creates the local object but does not attempt to validate or save it to the DB.
https://stackoverflow.com/a/2472416/2785289

Tutorial Michael Hartl at 9.4 failure when db:populate (admin part)

I didn't do the admin part on my application. I have just completed the chapter 10, but now I want to have an admin user.
I add the test, I try to verify in console doing that :
$ rails console --sandbox
>> user = User.first
>> user.admin?
=> false
>> user.toggle!(:admin)
=> true
>> user.admin?
=> true
No problem and the tests are green.
Then I updated the sample data populator to make the first user an admin by default, but when I run :
$ bundle exec rake db:reset
$ bundle exec rake db:populate
$ bundle exec rake test:prepare
I've got an error with db:populate :
bundle exec rake db:populate
rake aborted!
Can't mass-assign protected attributes: admin
/home/tprails/RubyOnRails/new_app/lib/tasks/sample_data.rake:5:in `block (2 levels) in <top (required)>'
Tasks: TOP => db:populate
So here is my sample_data.rake :
namespace :db do
desc "Fill database with sample data"
task populate: :environment do
admin = User.create!(name: "Example User",
email: "example#railstutorial.org",
password: "foobar",
password_confirmation: "foobar",
admin: true)
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)
end
users = User.all(limit: 6)
50.times do
content = Faker::Lorem.sentence(5)
users.each { |user| user.microposts.create!(content: content) }
end
end
end
My user model user.rb
class User < ActiveRecord::Base
attr_accessible :email, :name, :password, :password_confirmation
has_secure_password
has_many :microposts, dependent: :destroy
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
validates :name, :presence => true,
:length => { maximum: 50 }
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 }
validates :password, :presence => true,
:length => { minimum: 6 }
validates :password_confirmation, presence: true
def feed
Micropost.where("user_id = ?", id)
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
And my migration : add_admin_to_users.rb
class AddAdminToUsers < ActiveRecord::Migration
def change
add_column :users, :admin, :boolean, default: false
end
end
I hope you understand my problem and sorry for my bad english,
Thanks for your help
EDIT : I modify to:
admin = User.create!(name: "Example User",
email: "example#railstutorial.org",
password: "foobar",
password_confirmation: "foobar")
admin.toggle!(:admin)
Is that the correct solution ?
Which Rails version are you using?
If Rails 4: you can remove attr_accessible :email, :name, :password, :password_confirmation since you'll have to use strong parameters in the controller.
If Rails 3: add :admin to attr_accessible :email, :name, :password, :password_confirmation
You get the error because on db population, you're trying to mass assign all values at once:
admin = User.create!(name: "Example User",
email: "example#railstutorial.org",
password: "foobar",
password_confirmation: "foobar",
admin: true)
The error wouldn't turn up if you would add each value step by step like this:
admin = User.new
admin.name = "Example User"
...
admin.save
More infos here: Quck Look Strong Parameters and GitHub: Strong Parameters

Mass Assignment confusion in rails association

Having some trouble with something I'm sure is basic, but also having trouble finding a good answer here on SO.
I have a Users table and an Authorization table, here are my models:
##Authorization.rb
class Authorization < ActiveRecord::Base
attr_accessible :provider, :uid, :user_id
belongs_to :user
validates :provider, :uid, :presence => true
def self.find(auth_hash)
find_by_provider_and_uid(auth_hash["provider"],
auth_hash["uid"])
end
def self.create_with_hash(auth_hash)
#if they've already registered, then just return that authorization
unless auth = find_by_provider_and_uid(auth_hash["provider"],
auth_hash["uid"])
user = User.create(name: auth_hash["info"]["name"],
email: auth_hash["info"]["email"],
nickname: nil,
firstname: auth_hash["info"]["first_name"],
location: auth_hash["user_location"]
)
auth = create(user: user,
provider: auth_hash["provider"],
uid: auth_hash["uid"])
end
auth
end
end
And my User model:
##User.rb
require 'bcrypt'
class User < ActiveRecord::Base
include BCrypt
#accessible and settable properties
attr_accessible :name, :email, :nickname, :firstname, :location
#relations
has_many :authorizations, dependent: :destroy
#validations
validates :name, :email, :firstname, :presence => true
validates :email, :uniqueness => true
validates :nickname, :uniqueness => true
#always make sure their email and nickname are lowercased
def before_validation(user)
user.email.downcase!
user.email = Password.create(email)
user.nickname.downcase!
end
def after_save(user)
user.email = Password.new(user.email)
end
def is_nickname_available?(nickname)
Users.find_by_nickname(nickname.downcase).blank?
end
def add_nickname(user_id, nickname)
#todo: error handling
user = Users.find(user_id).update_attribute(nickname: nickname)
end
def add_provider(auth_hash)
#Check if the provider already exists, so we don't add it twice
unless
authorizations.find_by_provider_and_uid(auth_hash["provider"],
auth_hash["uid"])
Authorization.create user_id:self.id,
provider: auth_hash["provider"],
uid: auth_hash["uid"]
end
end
end
In a controller, if I try to do: Authorization.create_with_hash(auth_hash), I get the error:
Can't mass-assign protected attributes: user
On the line auth = create(user: user,
provider: auth_hash["provider"],
uid: auth_hash["uid"]) in my Authorization.rb model.
So, I'm very new to this, but am not clear on why this doesn't work. Can someone explain what I'm doing wrong?
Thanks
Mustafa
Use attr_accessible :provider, :uid, :user should work. Or change
auth = create(user: user,
provider: auth_hash["provider"],
uid: auth_hash["uid"])
to
auth = create(user_id: user.id,
provider: auth_hash["provider"],
uid: auth_hash["uid"])

Factory_girl simple association between two models

FactoryGirl.define do
factory :agency do
name "Example Inc"
available_items "20"
recruiter # recruiter.id
end
factory :recruiter do
email 'example#example.com'
password 'please'
password_confirmation 'please'
# required if the Devise Confirmable module is used
# confirmed_at Time.now
end
end
agency.rb
class Agency < ActiveRecord::Base
belongs_to :recruiter
validates :name, :presence => true
end
recruiter.rb
class Recruiter < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
attr_accessible :agency_attributes, :first_name
has_one :agency, :dependent => :destroy
accepts_nested_attributes_for :agency
validates :email, :presence => true
end
authentication_steps.rb
def create_user
#recruiter = FactoryGirl.create(:recruiter)
end
How can I replicate this Recruiter & Agency association using factory_girl?
I think you should remove recruiter from agency factory and add agency to requiter factory
FactoryGirl.define do
factory :agency do
name "Example Inc"
available_items "20"
factory :agency_without_recuiter do
recuiter_id = 1
end
factory :agency_with_recuiter do
recuiter
end
end
factory :recuiter do
email 'example#example.com'
password 'please'
password_confirmation 'please'
factory :recuiter_with_agency
agency
end
end
end
This should work from both sides
create(:agency).recuiter => nil
create(:agency_with_recuiter).recuiter => recuiter
create(:recuiter).agency => nil
create(:recuiter_with_agency).agency => agency
Hope it will be usefull. Good luck!
I think you have to replicate it in your test cases, not in FG itself.
before (:each) do
#recruiter = FactoryGirl.create(:recruiter)
#agency = FactoryGirl.create(:agency)
#agency.recruiter = #recruiter
end
Something like this.

Admin role isn't being assigned in my seed data when I have roles in my model?

In my seed file I am trying to create 3 users, 1 admin and 2 default users but it keeps assigning all 3 users to the default role before creation. Here is my code:
User.rb
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation, :remember_me, :username
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
has_many :user_prices
has_many :products, :through => :user_prices
validates_presence_of :username, :email, :password, :password_confirmation
validates_format_of :username, :with => /\A[a-z0-9]{5,20}\z/i
validates_uniqueness_of :username, :email
before_create :setup_default_role_for_new_users
ROLES = %w[admin default]
private
def setup_default_role_for_new_users
if self.role.blank?
self.role = "default"
end
end
end
Seed.rb
puts 'Loading seed data now....'
user1 = User.create(:email => 'admin#email.com', :role => 'admin')
user2 = User.create(:email => 'user1#email.com')
user3 = User.create(:email => 'user2#email.com')
puts 'Users added'
I know user2 and user3 will have the default role but user1 should be admin. How is this done?
since :role isnt in your accessible attributes, its protected from mass assignment, which is what you are doing in your seed file.
so in order to set role, you can use something like this
user1 = User.create(:email => 'admin#email.com')
user1.update_attribute(:role, 'admin')
Use if not unless:
def setup_default_role_for_new_users
if self.role.blank? # if not unless
self.role = "default"
end
end

Resources