How to skip after_build callback in factories? - ruby-on-rails-3

I'm facing a problem while creating a factory. I have a factory like:
Factory.define :job do |j|
j.association :service_partner, :factory => :service_partner
j.price_per_task 1.to_money
end
j.after_build{|j| j.project.service_partner_ids = [j.service_partner.id] unless j.service_partner.nil?}
end
How can I skip the after_build while creating factory?

If you only want to have the after_build callback to run occasionally, your best bet is to define a nested factory:
Factory.define :job do |j|
j.association :service_partner, :factory => :service_partner
j.price_per_task 1.to_money
end
factory :job_with_additional_setup do
j.after_build{|j| j.project.service_partner_ids = [j.service_partner.id] unless j.service_partner.nil?}
end
end
You can then create a normal job by doing FactoryGirl.create(:job) or one with the after_build: FactoryGirl.create(:job_with_additional_setup)

Related

Best way to modify factory attributes for multiple tests?

Trying to test some routing with rspec and factories. What would be the best way to modify an existing factory multiple times inside the spec test?
require "spec_helper"
describe gameController do
describe "routing" do
game = FactoryGirl.create(:game)
it "routes to #show" do
get("/game/1").should route_to("game#show", :id => "1")
end
it "routes to #show" do
# need to modify 1 param of the factory.. how best to do this?
get("/game/1").should route_to("game#show", :id => "1")
end
end
end
You basically have two options. If you're just modifying a single param between test, it might be easiest just to do something like:
before(:each) do
game = FactoryGirl.create(:game)
end
it "does something" do
get("/game/1").should route_to("game#show", :id => "1")
end
it "does something else" do
game.update_attributes(:param => "value")
get("/game/1").should route_to("game#show", :id => "1")
end
Otherwise, you could set up a factory girl sequence and do a fresh FactoryGirl.create in each spec.

Stub associations

I have method and spec.
class Event
def self.renew_subscription(user)
subscription = user.subscription
result = subscription.renew
user.pay(subscription.plan.price_in_cents) if result
result
end
end
let!(:user) { create :user }
describe ".renew_subscription" do
before do
user.subscription.stub!(:renew).and_return(true)
user.subscription.stub!(:plan).
and_return(Struct.new("SP", :price_in_cents).new(699))
end
context "when have to pay" do
it "pays" do
user.should_receive(:pay)
Event.renew_subscription user
end
end
end
There user belongs_to :subscription and subsription belongs_to :plan
Is there the way to stub subscription.renew and subscription.plan (or subscription.plan.price_in_cents)?
I think it's probably safe for you to do something like this:
Subscription.any_instance.stub(:renew).and_return(true)
plan = mock_model(Plan)
Subscription.any_instance.stub(:plan).and_return(plan)
plan.stub(:price_in_cents).and_return(699)
There are probably other ways of doing it too, but I hope that helps.

Rails 3: Find parent of polymorphic model in controller?

I'm trying to find an elegant (standard) way to pass the parent of a polymorphic model on to the view. For example:
class Picture < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
end
class Employee < ActiveRecord::Base
has_many :pictures, :as => :imageable
end
class Product < ActiveRecord::Base
has_many :pictures, :as => :imageable
end
The following way (find_imageable) works, but it seems "hackish".
#PictureController (updated to include full listing)
class PictureController < ApplicationController
#/employees/:id/picture/new
#/products/:id/picture/new
def new
#picture = imageable.pictures.new
respond_with [imageable, #picture]
end
private
def imageable
#imageable ||= find_imageable
end
def find_imageable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
end
Is there a better way?
EDIT
I'm doing a new action. The path takes the form of parent_model/:id/picture/new and params include the parent id (employee_id or product_id).
I'm not sure exactly what you're trying to do but if you're trying to find the object that 'owns' the picture you should be able to use the imageable_type field to get the class name. You don't even need a helper method for this, just
def show
#picture = Picture.find(params[:id])
#parent = #picture.imagable
#=> so on and so forth
end
Update
For an index action you could do
def index
#pictures = Picture.includes(:imagable).all
end
That will instantiate all 'imagables' for you.
Update II: The Wrath of Poly
For your new method you could just pass the id to your constructor, but if you want to instantiate the parent you could get it from the url like
def parent
#parent ||= %w(employee product).find {|p| request.path.split('/').include? p }
end
def parent_class
parent.classify.constantize
end
def imageable
#imageable ||= parent_class.find(params["#{parent}_id"])
end
You could of course define a constant in your controller that contained the possible parents and use that instead of listing them in the method explicitly. Using the request path object feels a little more 'Rails-y' to me.
I just ran into this same problem.
The way I 'sort of' solved it is defining a find_parent method in each model with polymorphic associations.
class Polymorphic1 < ActiveRecord::Base
belongs_to :parent1, :polymorphic => true
def find_parent
self.parent1
end
end
class Polymorphic2 < ActiveRecord::Base
belongs_to :parent2, :polymorphic => true
def find_parent
self.parent2
end
end
Unfortunately, I can not think of a better way. Hope this helps a bit for you.
This is the way I did it for multiple nested resources, where the last param is the polymorphic model we are dealing with: (only slightly different from your own)
def find_noteable
#possibilities = []
params.each do |name, value|
if name =~ /(.+)_id$/
#possibilities.push $1.classify.constantize.find(value)
end
end
return #possibilities.last
end
Then in the view, something like this:
<% # Don't think this was needed: #possibilities << picture %>
<%= link_to polymorphic_path(#possibilities.map {|p| p}) do %>
The reason for returning the last of that array is to allow finding the child/poly records in question i.e. #employee.pictures or #product.pictures

How can I map between strings and attributes automatically?

I have a tiny logical error in my code somewhere and I can't figure out exactly what the problem is. Let's start from the beginning. I have the following extension that my order class uses.
class ActiveRecord::Base
def self.has_statuses(*status_names)
validates :status,
:presence => true,
:inclusion => { :in => status_names}
status_names.each do |status_name|
scope "all_#{status_name}", where(status: status_name)
end
status_names.each do |status_name|
define_method "#{status_name}?" do
status == status_name
end
end
end
end
This works great for the queries and initial setting of "statuses".
require "#{Rails.root}/lib/active_record_extensions"
class Order < ActiveRecord::Base
has_statuses :created, :in_progress, :approved, :rejected, :shipped
after_initialize :init
attr_accessible :store_id, :user_id, :order_reference, :sales_person
private
def init
if new_record?
self.status = :created
end
end
end
Now I set a status initially and that works great. No problems at all and I can save my new order as expected. Updating the order on the other hand is not working. I get a message saying:
"Status is not included in the list"
When I check it seems that order.status == 'created' and it's trying to match against :created. I tried setting the has_statuses 'created', 'in_progress' etc but couldn't get some of the other things to work.
Anyway to automatically map between string/attribute?
from your description, looks like you're comparing a string to a symbol. Probably need to add:
define_method "#{status_name}=" do
self.status = status_name.to_sym
end
or do a #to_s on the status_names

Singleton factories in factory_girl/machinist?

Is there some configuration in a factory of factory girl/machinist that forces it to create objects with the same factory name just once during test case and return the same instance all the time? I know, i can do something like:
def singleton name
##singletons ||= {}
##singletons[name] ||= Factory name
end
...
Factory.define :my_model do |m|
m.singleton_model { singleton :singleton_model }
end
but maybe there is a better way.
You can use the initialize_with macro inside your factory and check to see if the object already exists, then don't create it over again. This also works when said factory is referenced by associations:
FactoryGirl.define do
factory :league, :aliases => [:euro_cup] do
id 1
name "European Championship"
owner "UEFA"
initialize_with { League.find_or_create_by_id(id)}
end
end
There is a similar question here with more alternatives: Using factory_girl in Rails with associations that have unique constraints. Getting duplicate errors
#CubaLibre answer with version 5 of FactoryBot:
FactoryGirl.define do
factory :league do
initialize_with { League.find_or_initialize_by(id: id) }
sequence(:id)
name "European Championship"
end
end
Not sure if this could be useful to you.
With this setup you can create n products using the factory 'singleton_product'. All those products will have same platform (i.e. platform 'FooBar').
factory :platform do
name 'Test Platform'
end
factory :product do
name 'Test Product'
platform
trait :singleton do
platform{
search = Platform.find_by_name('FooBar')
if search.blank?
FactoryGirl.create(:platform, :name => 'FooBar')
else
search
end
}
end
factory :singleton_product, :traits => [:singleton]
end
You can still use the standard product factory 'product' to create a product with platform 'Test Platform', but it will fail when you call it to create the 2nd product (if platform name is set to be unique).