What's a reliable why to create a custom id for an associated item in rails - ruby-on-rails-3

I have a nested resource like this
resources :projects do
resources :tasks
end
The tasks have a field named number. Whenever I create a task I would like to give it a squential number within the parent project.
This is my model class
class Task < ActiveRecord :: Base
belongs_to :project
validate_presence_of :title
before_create :generate_number
private
def generate_number
if project.tasks.nil? || project.tasks.count < 1
self.number = 1
else
self.number = list.topics.count+1
end
end
end
I am not sure about certain things:
Does this logic belongs in my Task Model or in my Project model or in a seperate class/module?
What is the best before filter. (before_create, before_validation, validation)?
Because there are many ways how to create a task. With a list, in a list, alone and then attach it to a list...
And which filter would work in my tests so that I could setup some Fakes for example with factory girl... Because right now FactoryGirl does not always executes generate number...
This is my factory
FactoryGirl.define do
factory :project do
name "Hello world"
end
trait :with_tasks do
ignore do
number_of_tasks 3
end
after :create do |project,evaluator|
#project.Factory.create_list :taks, evaluator.number_of_tasks, :project => project
end
end
end
What would be the best. reliable way to generate a sequential custom taks number depending on the project which works in my specs as well as in production?
Any best practise tips would be appreciated.

I would keep the before_create callback in the Task model, which would call the generate_number function. This should work in Factory girl where it would add the number if you use Factory.create, but not when you use Factory.build.

Related

How to test for deleting an association in FactoryGirl?

I have the following factory:
factory :store do
room
factory :store_with_items do
ignore do
items_count 4
end
after(:create) do |store, evaluator|
FactoryGirl.create_list(:equippable_item, evaluator.items_count, store: store)
end
end
end
Next, I create an object:
#store = FactoryGirl.create :store_with_items
My problem is that when I "delete" one of the store's items, the store still shows that it has 4 items.
#store.items[0].store_id = nil
#store.save!
puts #store.items.size
The puts is 4. How do I properly delete an item? Isn't this how you would do it in rails?
I used to prefer this approach, but now I avoid it; its easier and more flexible to let factories be simple and populate has_many associations at runtime.
Try this
Factory for store (same):
factory :store do
room
end
Factory for items:
factory :item do
store # will use the store factory
end
Then in my test I would populate what is appropriate for the case at hand:
#store = FactoryGirl.create :store
#item1 = FactoryGirl.create :item, store: #store
#item2 = FactoryGirl.create :equippable_item_or_whatever_factory_i_use, store: #store
To explain
By passing in the store instance explicitly, the association will be setup for you. This is because when you pass something explicitly in FactoryGirl.create or FactoryGirl.build it overrides whatever is defined in the factory definition. It even works with nil. This way, you'll have real object instances that give you all the real functionality.
To test destroy
I think the code in your example is not good; it breaks the association between store and item, but doesn't actually remove the item record so you're leaving behind an orphan record. I would do this instead:
#store.items[0].destroy
puts #store.items.size
Bonus
You probably also want to setup your child associations to be destroyed when the parent is destroyed if its not already. This would mean when you say #store.destroy all the items belonging to it will also be destroyed (removed from the db.)
class Store < ActiveRecord::Base
has_many :items, dependent: :destroy
.....
end

Rspec, FactoryGirl unable to find ActiveRecord method

I am trying to learn Rspec in a very simple CRUD Rails 3.2.8 app. I'm following the general pattern of Michael Hartl's examples and have been moderately successful with cucumber for the outside in portion. Now I want to test a Twilio SMS feature and cannot seem to get to first base, mostly because I'm not asking the right questions, so I expect to be corrected here and get back on track.
My app has two models, commodity and price and they interact with each other in my cucumber tests, so it appears. I'm aware, like in cucumber, I need an object to start to test its interactions. In my prices controller, I see that I can get the commodity's prices with the below in my prices#create method:
#price = #commodity.prices.build(params[:price])
I ultimately want to generate a factory that will have many prices for a given commodity. But I want to get to base first. Following thoughtbot's examples on their Readme I'm attempting the following in rails console:
FactoryGirl.create(:commodity) do |price|
Commodity.prices.build(attributes_for(:price))
end
The result is: NoMethodError: undefined method `prices' for #
Hmm, I must not be understanding either Rspec or Factory Girl. Here is my basic factories.rb:
FactoryGirl.define do
factory :commodity do
name "corn"
end
sequence :price do |n|
price
date { Time.now }
end
end
Here are my two models:
class Commodity < ActiveRecord::Base
attr_accessible :description, :name
has_many :prices
end
MOST_RECENT = 5
class Price < ActiveRecord::Base
attr_accessible :buyer, :date, :price, :quality, :commodity_id
scope :most_recent, lambda { order("id desc").limit(MOST_RECENT) }
belongs_to :commodity
end
My attempt to understand this is to do it simply in Rails console but the error also appears when I run rspec as well. But why would FactoryGirl, or Rspec, not seem to use the prices method I get with Active Record? Clearly, I'm not understanding something or I would have found the answer on Stack, thanx, sam
In your FactoryGirl.create there are a couple problems. First, the block argument should be commodity, not price. create passes the created object into the block. Second, you're trying to run prices on the Commodity class. In your object relationship, prices is an accessor associated with a specific instance. There is no Commodity#prices method, but any given instance of Commodity will have prices. You can probably use build like that, but I think the canonical way is to use the shift operator to add a Price.
Putting this together gets you:
FactoryGirl.create(:commodity) do |commodity|
commodity.prices << FactoryGirl.create(:price, commodity: commodity)
end
I'm not sure what you're doing with the sequence in your Commodity factory definition. If you're trying to make sure that Commodities are created with Prices by default (without adding them as above), check out some of the tips at http://icelab.com.au/articles/factorygirl-and-has-many-associations/.

Associated records via custom query in Rails

I have two models that are connected via a has_many/belongs_to association:
Class Project < ActiveRecord::Base
has_many :tasks
end
Class Tasks < ActiveRecord::Base
belongs_to :project
end
Each of the tasks are tagged with a HABTM relationship:
Class Tasks < ActiveRecord::Base
belongs_to :project
has_and_belongs_to_many :tags
end
I am trying to get a list of projects based on a tag id. I can get a list of projects that have tasks with a specific tag by using a class method on my Project model:
def by_tag(tag_id)
Project.joins(:tasks => :tags).where(:tags => {:id = tag_id})
end
Ideally, I'm looking to be able to list all the projects and their associated tasks for a given tag in my view. I could normally get a list of tasks belonging to a given project by using project.tasks if I used a typical find with project like Project.find(1).
However, when I try project.tasks on results found using my new class method Project.by_tag(1), I get a "NoMethodError: Undefined Method 'tasks'" error.
I looked into Named Scopes to get the Project by Tag results but it seems like people are moving away from that approach in favor of class methods. Is that true?
On your project model you need to add it to the class not the instance. Also note that this raises the self object to the class so you can eliminate "Project." unless you want to be explicit.
class << self
def by_tag(tag_id)
joins(:tasks => :tags).where(:tags => {:id = tag_id})
end
end
There is always debate over what is the best method. I myself prefer whatever gets the job done quicker. I like scopes personally but to each his own.

devise after create hook

Is there a hook or callback that I can implement so that right after the user is created, I would like to invoke some custom code ?
I tried after_confirmation hook in the user model but that didn't work.
Use the standard after_create callback provided by Rails.
class User < ActiveRecord::Base
after_create :do_something
def do_something
puts "Doing something"
end
end
Using a callback is perfectly legit if you're dealing with the internal state of the model you created.
After creating a User, I needed to create default a Team. It's preferable to avoid using callbacks to deal with other objects.
“after_*” callbacks are primarily used in relation to saving or persisting the object. Once the object is saved, the purpose (i.e. responsibility) of the object has been fulfilled, and so what we usually see are callbacks reaching outside of its area of responsibility, and that’s when we run into problems.
From this awesome blog post.
In this case it's better to act on the controller, where you can add your functionality directly, or delegate to a service for an even cleaner solution:
# shell
rails g devise:controllers users
# config/routes.rb
devise_for :users, controllers: { registrations: "users/registrations" }
# app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
after_action :create_default_team, only: :create
private
def create_default_team
Team.create_default(#user) if #user.persisted?
end
end
I'm using Rails 4 with Devise 3.5 with confirmable and had to do this due to various surprises.
class User < ActiveRecord::Base
# don't use after_create, see https://github.com/plataformatec/devise/issues/2615
after_commit :do_something, on: :create
private
def do_something
# don't do self.save, see http://stackoverflow.com/questions/22567358/
self.update_column(:my_column, "foo")
end
end

How to hanlde list data that doesn't belong to a model an isn't a model by its own in rails?

In my rails project I have diferent list of data that I have to mantain with CRUD operations and each list doesn't deserve a model or an entire scaffolding to maitain it, what's the best way to handle this on rails?
Now I'm using a List model with name:string content:text to save each list as a list record and do some parsing when I need some list in my app. Here is my actual list model:
class NoListException < Exception
end
class List < ActiveRecord::Base
validates :name, uniqueness: true
def self.container_types
get_list('container_types').collect do |b|
b.split(',').collect {|c| c.split(':').last }
end.collect {|p| "#{p.last} - #{p.first}" }
end
def self.location_categories
get_id_value_list('location_categories')
end
def self.services_types
get_list('services_types')
end
private
def self.get_id_value_list(name)
get_list(name).collect do |b|
(b.split(',').collect {|c| c.split(':').last }).rotate
end
end
def self.get_list(name)
list = List.find_by_name(name)
raise NoListException if list.nil?
list.content.split(';')
end
end
I think is a very common problem, because of that I ask if there are a better way to handle those lists?
Its not bad to have a model with no scaffolding to support it. I often do this with category or tag like models which are often created and managed by the models they act upon. So don't feel pressured to build out a whole scaffolding for a simple model.
If you don't need to persist the data to the database then you can always use ActiveModel, or if you do need to persist and can find another model to piggy back ontop of, look into serialization, its a good way to store loose data