Undefined method after_create with FactoryGirl - ruby-on-rails-3

I'm trying to defined a has_many relationship in FactoryGirl using the after_create callback, like so in /spec/factories/emails.rb:
FactoryGirl.define do
factory :email do
after_create do |email|
email.attachments << FactoryGirl.build(:attachment)
end
end
end
The attachment is defined in a seperate factory /spec/factories/attachment.rb:
FactoryGirl.define do
factory :attachment do
# Attach the file to paperclip
file { fixture_file_upload(Rails.root.join('spec', 'support', 'myimage.png'), 'image/png') }
end
end
Using the :attachment in my specs works absolutely fine, so I'm confident that the factory for that is not the problem, however when I try and create an :email from the factory I get the following exception thrown:
Failure/Error: email = FactoryGirl.create(:email)
NoMethodError:
undefined method `after_create=' for #<Email:0x007ff0943eb8e0>
I'm at a bit of a loss as to what to do, can't seem to find any one else getting the same error.

FactoryGirl recently changed the syntax for callbacks. I think the following will work:
FactoryGirl.define do
factory :email do
after(:create) do |email|
email.attachments << FactoryGirl.build(:attachment)
end
end
end

Related

Rails 3 & Strong Parameters, getting mass assignment errors

I'm trying to use strong parameters in a single model in my Rails 3 project that has around 40-50 models.
I've done the following, but when I try to create or update an instance of this model, I get the same error regarding mass assignment, as below, which shows every field of the model.
I've tried removing the accepted_nested_attributes_for from the model and restarting the webserver, but it didn't have an effect on the error I'm receiving.
config/application.rb
config.active_record.whitelist_attributes = false
app/models/my_service.rb (concatenated for brevity)
class CallService < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection
belongs_to :account
has_many :my_service_chargeables
accepts_nested_attributes_for :my_forward_schedules, allow_destroy: true
validates :start_date, :username, :account_id, :plan_id, presence: true
audited associated_with: :account
scope :enabled, where(enabled: true)
scope :within, lambda{|month| where(start_date: (month.beginning_of_month..month.end_of_month))}
end
app/controllers/my_services_controller.rb
def update
#my_service = MyService.find(params[:id])
if #my_service.update_attributes(permitted_params.my_service)
flash[:success] = "Service Updated"
redirect_to #my_service
else
render 'edit'
end
end
app/controllers/application_controller.rb
def permitted_params
#permitted_params ||= PermittedParams.new(current_user, params)
end
app/models/permitted_params.rb
class PermittedParams < Struct.new(:user, :params)
def my_service
if user && user.role?(:customer)
params.require(:my_service).permit(*service_customer_attributes)
else
params.require(:my_service).permit!
end
end
def service_customer_attributes
[:timeout, :pin, :day]
end
end
ERROR WHEN UPDATING
ActiveModel::MassAssignmentSecurity::Error in MyServicesController#update
Can't mass-assign protected attributes: account_id, plan_id, start_date, username
I've run a debugger to confirm the code hits the params.require(:my_service).permit! line from the PermittedParams class, yet this exception still keeps getting thrown, when as far as I can tell, there should be nothing causing this model to require declaring attributes as attr_accessible's.
Can anyone shed some light on this behavior?
I'm using gem versions (from my Gemfile.lock):
strong_parameters (0.2.0)
rails (3.2.11)
I'm not sure what your exact use case is, but doing params.require(:my_service).permit! still seems like a bad idea here, at the very least someone could still override your model's PK. Rather than params.require(:my_service).permit! why not do:
params.require(:my_service).permit(:timeout, :pin, :day, :account_id,
:plan_id, :start_date, :username)
Or keep these in another array and merge them with your existing service_customer_attributes to keep it DRY.
This would take care of your mass assignment error, and will be more secure and more explicit.

Scope but error message ArgumentError: tried to create Proc object without a block

I am tring to create a scope which find out all contacts with 0 address. Got error message ArgumentError: tried to create Proc object without a block when running command 'Contact.noaddress' in rails c.
Here is my contact model including scope:
class Contact < ActiveRecord::Base
attr_accessible :email, :firstname, :lastname, :mobilephone, :fullname
has_many :addresses
validates_presence_of :firstname, :lastname
scope :noaddressed, lambda do |addresses|
joins(:addresses).where('addresses.created_at.empty?', true)
end
end
and here's address model
class Address < ActiveRecord::Base
attr_accessible :city, :country, :postalcode, :region, :street
belongs_to :contact
end
Could somebody help me please?
It sounds like a (precedence issue?) referenced here.
If you change the scope to:
scope :noaddresses, (lambda do
joins(:addresses).where('addresses.created_at is null')
end)
or
scope :noaddresses, lambda { joins(:addresses).where('addresses.created_at is null') }
Also, I don't see where you're using the block argument |addresses|. Did you forget to use it? Otherwise, you can remove it and its surrounding pipes.
Updated: I removed the |addresses| argument and updated the query to be valid SQL syntax.

How can I have associations properly set in Factory Girl?

I am new to FactoryGirl. I come from the fixtures world.
I have the following two models:
class LevelOneSubject < ActiveRecord::Base
has_many :level_two_subjects, :inverse_of => :level_one_subject
validates :name, :presence => true
end
class LevelTwoSubject < ActiveRecord::Base
belongs_to :level_one_subject, :inverse_of => :level_two_subjects
validates :name, :presence => true
end
And I would like to do something like the following in factories:
FactoryGirl.define do
factory :level_one_subject, class: LevelOneSubject do
factory :social_sciences do
name "Social Sciences"
end
end
factory :level_two_subject do
factory :anthropology, class: LevelTwoSubject do
name "Anthropology"
association :level_one_subject, factory: social_sciences
end
factory :archaelogy, class: LevelTwoSubject do
name "Archaelogy"
association :level_one_subject, factory: social_sciences
end
end
end
Then when I use the factory in a spec like this:
it 'some factory test' do
anthropology = create(:anthropology)
end
I get the error:
NoMethodError: undefined method `name' for :anthropology:Symbol
Can anybody help here?
If I do not set the association in factory, then I do not get this error, but I get the error that level_one_subject_id has to be present and only the following test code works:
it 'some factory test' do
social_sciences = create(:social_sciences)
anthropology = create(:anthropology, :level_one_subject_id => social_sciences.id)
end
But I really want to know why the factory with the association does not work. With Fixtures I had all this for nothing.
I think you are trying to group factories by a 'class factory', which is not how FactoryGirl works. It will deduce the ActiveRecord class from the factory name itself, if named appropriately. In case, your factory name is not the same as the class name, we need to explicitly specify the class name using class named parameter. This should work:
FactoryGirl.define do
factory :level_one_subject do # automatically deduces the class-name to be LevelOneSubject
name "Social Sciences"
end
factory :anthropology, class: LevelTwoSubject do
name "Anthropology"
level_one_subject # associates object created by factory level_one_subject
end
factory :archaelogy, class: LevelTwoSubject do
name "Archaelogy"
level_one_subject # associates object created by factory level_one_subject
end
end

Rail 3.2.2/Devise: deprecation warning with rspec

I recently upgraded an app to rails 3.2.2.
I'm using Factory_girl
Factory.sequence :name do |n| "name-#{n}" end
Factory.define :user do |u| u.first_name{ Factory.next(:name) }
u.last_name { |u| 'last_' + u.first_name } u.password 'secret'
u.password_confirmation { |u| u.password } u.sequence(:email) { |i|
"user_#{i}#example.com" }
end
and this simple test
specify { Factory.build(:user).should be_valid }
generate the following warning
DEPRECATION WARNING: You're trying to create an attribute user_id'.
Writing arbitrary attributes on a model is deprecated. Please just use
attr_writer` etc. (called from block (2 levels) in
at...
How can I get rid of it?
It's probably because you haven't prepared/migrated your test database with updated column definitions, thus it thinks you're trying to arbitrarily set the attribute.
Run rake db:test:prepare to make sure it's updated.
Here's the source code of that method, where you can see Rails checks for the column or attribute first, then warns if they're not found.
I've met the same warning with the following code:
Ad model:
class Ad < ActiveRecord::Base
belongs_to :user
end
Factories:
FactoryGirl.define do
factory :ad do
association :user
end
end
FactoryGirl.define do
factory :user do
first_name {Factory.next(:first_name)}
last_name {Factory.next(:last_name)}
email {|x| "#{x.first_name}.#{x.last_name}#{Factory.next(:count)}#test.com"}
password Forgery(:basic).password
confirmed_at Date.today << 10
end
end
Test
require 'spec_helper'
describe Ad do
before(:each) do
#ad = Factory.build(:ad)
end
"it is not valid without a user"
end
Running the test gave me a similar error.
Adding
attr_accessor :user
to the Ad model fixed the warning.
I hope it helps.
I had this same warning while doing tests in Rspec and my issue was that I had a Parent model and Child model where I accidentally had this:
class Child < ActiveRecord::Base
belongs_to :parent
end
......
class Parent < ActiveRecord::Base
belongs_to :child
end

How to access the passed-in parameters hash in FactoryGirl

I am working on a web backend in Rails. My Article model is largely a wrapper that delegates most methods to the most recent ArticleVersion. When writing FactoryGirl factories, though, I was trying to create an :article_with_version factory that generates an Article and gives it a version, but I'm not sure how to forward parameters from the Article factory on to the ArticleVersion.
Here is the relevant code:
class Article < ActiveRecord::Base
has_many :versions, :class_name => "ArticleVersion"
def title
self.versions.last.title
end # method title
def contents
self.versions.last.contents
end # method contents
end # model Article
FactoryGirl.define do
factory :article_version do; end
factory :article do; end
factory :article_with_version, :parent => :article do
after_create do |article|
article.versions << Factory(:article_version, :article_id => article.id)
end # after_create
end # factory :article_with_version
end # FactoryGirl.define
What I would like to be able to do is call Factory(:article_with_version, :title => "The Grid", :contents => "<h1>Greetings, programs!</h1>") and have FactoryGirl pass those :title and :contents parameters on to the new ArticleVersion (or nil if those are omitted). Is there a way to access that hash of dynamic parameters that are passed on during Factory.create()?
You can do it using transient attributes like this:
factory :article_with_version, :parent => :article do
ignore do
title nil
contents nil
end
after_create do |article, evaluator|
article.versions = [FactoryGirl.create(:article_version, title: evaluator.title, contents: evaluator.contents)]
article.save!
end
end
Just note that the attributes being ignored will not be set on the Article itself, although it looks like that is the behaviour you want in this case.