Rails FactoryGirl trait association with model after_create callback not setting vanity_url
Asked Answered
P

2

2

In my model, I have an after_create callback that triggers the method:

class Job < ActiveRecord::Base
  after_create :update_vanity_url

  private

  def update_vanity_url
    self.vanity_url = '/jobs/' + company.slug + '/' + slug + '/' + id.to_s + '/'
  end
end

This sets up a custom url for my jobs, however, when I try to use this in my coupon factory it is not being saved. The coupon is created without a job assigned. Only when the coupon is used is it paired with one job. I referred to that as executed:

FactoryGirl.define do
  factory :coupon do
    code { rand(25**25) }
    percent_discount { rand(100**1) }
    start_at { Time.now }
    end_at { 30.day.from_now }

    trait :executed do |c|
      association :job, factory: [:job, :purchased] 
      c.executed_at { Time.now }
    end
  end
end

Ideally, I would like to be able to call FactoryGirl.create(:coupon, :executed) which works but the after_create is never called... Thoughts?

More details of this setup are covered here Rails FactoryGirl Factory with optional model association

Per issue comments below, I have added my routes section and updates:

Routes

  resources :jobs, only: [:new] do
    collection do
      post 'new', to: 'jobs#create'
    end
    get '/review', to: 'reviews#new'
    patch '/review', to: 'reviews#update'
    get '/payment', to: 'payments#new'
    patch '/payment', to: 'payments#update'
  end
  match '/jobs/:company_slug/:job_slug/:id', via: :get, to: 'jobs#show'
Paquin answered 11/3, 2016 at 21:42 Comment(0)
P
0

I researched this for hours, and this is what I found to work. It turns out it was not FactoryGirl, rather the model itself... I think...

  def update_vanity_url
    self.vanity_url = '/jobs/' + company.slug + '/' + slug + '/' + id.to_s + '/'
    save
  end
Paquin answered 12/3, 2016 at 0:28 Comment(2)
I would reconsider this approach. Your model should not be responsible for routing. Rather this should be handled in your routes.rb file. What you want to have in your model is a '.find_by_id_or_slug' method.Color
I tried that approach, but the vanity urls seem to work better per the client SEO spec. Take a look at my routes I posted, it works like normal rails for everything else, outside the match portion @ColorPaquin
B
0

Your actual question

The problem you're asking about is more a symptom or side effect of how you're doing your lookup.

tl;dr: The vanity_url attribute is not being saved because update_vanity_url is set on an after_create callback when the record has already been written to the database. It is setting it in memory which is why your tests might've been tripped up by this.

That's why putting save in the callback fixed your issue. It's simply saving a Job a second time after it's created. This is necessary because you wouldn't have the id before it was written to the database.

Maybe a better solution?

Are you doing anything with the vanity_url attribute besides routing to it? I ask because unless you're denormalizing this for speed you may not need to store this on the model at all.

The only thing I came up with is that you might be using those params to construct the vanity_url and doing something like @job = Job.where(vanity_url: vanity_url).first or something.

Belligerent answered 19/8, 2016 at 17:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.