I'm having trouble seeding my database using seed.rb, specifically where table relationships are concerned.
Here's a sample of the code:
# seed.rb
user = User.find_or_create_by_login(
:login => "myname",
:email => "myname#gmail.com",
:user_type => "Admin",
:password => "admin",
:password_confirmation => "admin")
project = Project.find_or_create_by_user_id(
:user_id => user.id,
:name => "Test Project")
When project is created (along with other unrelated parameters I've left out from above), user_id is empty. How can I get this to work?
This is the strangest behavior I've seen in something so simple. In my seed file, I have about eight tables being created and some are nested 3-4 levels deep (i.e. user has_many projects; projects has_many tasks, etc.).
When I call user user as above and reference user.id multiple times after that, it only works once! I tried adding [user.reload] before each new record is created but to no avail. I don't imagine this will make sense to anyone, but are there any possibilities here? Thanks all.
I figured out what the problem was. The fields that weren't populating were not listed explicitly in attr_accessible in their respective models. The fields listed were being saved correctly.
Thank you very much for your help everyone.
The code is fine and is the correct syntax for find_or_create. As others have said the most likely problem is that the user is invalid. Trying to call user.reload would make it blow up if the user is invalid and so will kind of make the problem more apparent, but the error you'll get from it will be useless (it'll moan about not being able to find a user without an id).
Unfortunately find_or_create doesn't work as a bang method to raise exceptions if it's invalid, so the best thing to do is probably raising an error and outputting the error after attempting to create the user:
user = User.find_or_create_by_login(:login => "myname")
raise "User is invalid: #{user.errors.full_messages}" unless user.valid?
User created with success? if so..try user.reload if not. that is probably the error
Are you sure your user is saved? I think the right syntax for find_or_create_by_XX is Blog.find_or_create_by_title("Some Blog"). If you need to pass more data you need to use find_or_initialize first and set other data after that separately.
Loosely related thread: Rails find_or_create by more than one attribute?
--edit
Passing data as hash to find_or_create_by_XX seems to work too. Docs are under "Dynamic attribute-based finders" here http://apidock.com/rails/v3.0.0/ActiveRecord/Base
try this
use User.find_or_create instead of User.find_or_create_by_login.
It seems like your user object is not saved.
Or before you assign user.id do user.reload
user = User.find_or_create(
:login => "myname",
:email => "myname#gmail.com",
:user_type => "Admin",
:password => "admin",
:password_confirmation => "admin")
[user.reload]
project = Project.find_or_create_by_user_id( :user_id => user.id,
:name => "Test Project")
Related
I know it is broad question but I am really confused.
I have table users and columns :username, :pwd_hash, :first_name, :last_name etc.
When I try to create new instance with
user = User.new(:username => 'Foo', first_name => 'Bar')
puts user.inspect
and I inspect user I get that all properties set to nil. If I do get existing user all is set properly with User.find(1) so DB is setup correctly. Also there are columns with same name in DB. Using ruby 1.9.3 on Windows.
Again I know it is stupid question but I am despreate I am wondering if anybody had similiar problem. Thank you.
This can happen if your User model uses attr_protected or attr_accessible to prevent username or first_name from being mass-assigned.
I've been using Factory Girl to create some basic objects in development when I want to test out an idea, and I commonly run into this:
ActiveRecord::RecordInvalid: Validation failed: Email has already been taken, Login has already been taken
If I've run FactoryGirl.create :user in development mode once and left that user in the db, I'll have to run that command twice if I try to do this again after closing the console. Basically, sequences are getting reset between console instances.
Has anyone come up with a way to write factories such that they'll generate unique results each time? I'm aware that I can use random generators to pick a value from a large domain, minimizing the chance of a collision. I'd like to find a cleaner method, if available, though.
You can write a sequence for this.
Factory.sequence(:email) do |n|
"tester#{n}#example.com"
end
Factory.define :user do |f|
f.name "Tester"
f.email {Factory.next :email}
f.password "tester"
end
Source: about half way down the page.
EDIT
Upon re-reading, it seems that you are trying to create the data in development mode.
You should use the seeds.rb file for this and maintain a counter.
index = User.count || 1
User.create([
{:email => "user#{index++}#example.com",
:password => "password"},
{:email => "user#{index++}#example.com",
:password => "password"}
])
I am new to ROR and been trying to fumble my way through the tutorial by mike hartl( excellent read for starters i might add ). There is however something i am struggling with, my user model looks like below.
class User < ActiveRecord::Base
validates :name , :presence => true, :length => {:maximum => 50 }
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => true
end
I then open the ruby console using rails -c and create a new user
usr = User.new(:name=>"abcd",:email=>"svsvenu#gmail.com")
I then save it by using
usr.save
This created a new record in my database. So far so good.but if i type
usr.save
again, nothing happens, i look at the database ( sqlite ) and not even the last update date changed.
Another interesting thing i noticed is when i use
User.create(:name=>"abcd",:email=>"svsvenu#gmail.com"),
multiple times, there is a record created every time i run it in the console.
Can some one please explain why my save does not work and also why my uniqueness constraint is being ignored?
Thanks in advance
ActiveRecord is smart enough to understand that when you type usr.save twice in a row, the 2nd one is redundant.
usr = User.new
usr.save # usr is saved (if it was valid)
usr.save # usr is already saved and unchanged! do nothing.
usr.name = "bananas"
usr.save # usr name changed, commit the change!
When you say that a user is created in the console each time you run User.create, are you sure they're actually being created? In console you'll see a User returned each time, but the id would be nil if there had been errors in the create attempt. If you run create! instead you'd see an exception if the User had validation errors (like a duplicate email) and did not save.
I've got a User model with three fields, :email, :display_name and :handle. Handle is created behind the scenes from the :display_name.
I'm using the following validations:
validates :display_name, :presence => :true, :uniqueness => { :message => "Sorry, another user has already chosen that name."}, :on => :update
validates :email, :presence => :true, :uniqueness => { :message => "An account with that email already exists." }
I use the handle as the to_param in the model. If the user fails the validation by submitting a :display_name that already exists, then tries to change it and resubmit the form, Rails seems to use the new handle as the validation for the email -- in other words, it assumes that the email doesn't belong to the current user and validation on the email then fails. At this point, Rails assumes that the changed display name/handle is the one to use for the look up and the update action can't complete at all, because it can't find the user based on the new handle.
Here's the update method:
def update
#user = User.find_by_handle(params[:id])
#handle = params[:user][:display_name]
#user.handle = #handle.parameterize
...
end
This problem doesn't happen when the validation first fails on a duplicate email, so I'm assuming it's something about the way I've written the update method -- maybe I should try setting the handle in the model?
maybe I should try setting the handle in the model?
^ This.
The controller isn't the place to do something like this. If it's model logic that's happening behind the scenes, beyond the user's control, why put it in controller code?
Do it instead in a before_save filter, which is guaranteed to run only after the chosen display name is determined to be available and the record is deemed valid. In this way the handle won't be changed on the cached record until it is actually committed to the db, eliminating the problem of the incorrectly generated URL.
before_save :generate_handle
...
def generate_handle
self.handle = display_name.parameterize
end
I need a "I accept terms of service" checkbox on a page, it has to be checked in order for the order to proceed. It seems hence illogical to have a column in the database to match this (whether user has accepted or declined terms).
I am using the form helper like this in my view:
<%= check_box("client", "terms") %>
And in my model:
validates_acceptance_of :terms
At the moment it is not working at all.
This seems like a really common piece of code, yet I can't find it used anywhere without having the terms in the model. Else I could use javascript to validate it, but would prefer to keep it all the in model.
This should work fine, without a database column or attr_accessor:
http://guides.rubyonrails.org/active_record_validations.html#acceptance
I would be inclined to check your params hash is as it should be i.e. that the 'terms' attribute is being passed within the 'client' hash, perhaps try adding raise params.inspect on your controller create action to help you debug?
What about having an attr_accessor :terms in your Client model?
I had this working with these settings:
In the controller, I have added :terms_of_service as a permitted field:
def application_params
params.require(:application).permit(. . . , :terms_of_service)
end
In the model:
attr_accessor :terms_of_service
validates :terms_of_service, :acceptance => true
In the view:
<%= f.check_box("terms_of_service", :checked => false) %>
attr_accessor :terms will do the trick nicely.
Either go with #neutrino's solution, or to reset :terms to "not accepted" if you need to redisplay the form (because validation may fail), use this:
def terms
nil
end
def terms=(val)
# do nothing
end