FactoryGirl belongs_to association - ruby-on-rails

I have a factory where I define a location in factories/locations.rb. I'm using Mongoid and Rails 3.1.1 with ruby 1.9.3.
FactoryGirl.define do
factory :location do
name Faker::Name.name
description "Down by the river"
end
end
And then I want to define a fitness camp which belongs_to a location (and therefore has a location_id attribute).
FactoryGirl.define do
factory :fitness_camp do
title "Parkour"
association :location_id, :factory => :location
end
end
This works but, is the result of my hacking, not what I read in the docs. From the getting started guide ( https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md) it seems this should be as simple as:
factory :fitness_camp do
title "Parkour"
location
end
Am I missing something? Does this indicate my models might not be configured correctly?
Thanks!
Tim

I was an idiot -- I had validates_numericality_of :location_id
class FitnessCamp
include Mongoid::Document
field :title, :type => String
belongs_to :location
validates_presence_of :location_id, :title
validates_numericality_of :location_id
Mad props to Radar (Ryan Bigg) for helping me through this.

Related

Ruby on Rails has_and_belongs_to_many uninitialized constant

I'm building a site on Refinery CMS, and have generated two extensions: one for Brands, and another for Bicycle Types (it's a site for a bike shop).
Now, what I want to do is have the Brands extension handle the creation of brand pages, which will be pulled into a brand index. On this page, I want to be able to filter by Bicycle Type, which is where the second extension comes in. Through the Bicycle Type extension, you can create a bicycle type, which I want to associate to a Brand. A Brand can have multiple Bicycle Types, and vice versa.
So, I edited the Brands model to add has_and_belongs_to_many :bicycle_types, and the Bicycle Types model to include has_and_belongs_to_many :brands and accepts_nested_attributes_for :brands. I wrote a migration to create a join table, and everything was going well so far.
I then went to modify the form for the Brands extension, and got my checkboxes displaying correctly and seemingly generating the right code. However, the problem occurs when I come to submit the form - I get NameError in Refinery::Brands::Admin::BrandsController#update and uninitialized constant Refinery::Brands::Brand::BicycleType.
The parameters I get look like the bicycle type IDs are being passed through correctly:
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"3193ZMPXkmHdgZThXwAurD6xF2eZ533Tb71pAi7Jxbs=",
"switch_locale"=>"en",
"brand"=>{"title"=>"Cannondale",
"teaser"=>"",
"splash"=>"",
"details"=>"",
"introduction"=>"",
"blockquote"=>"",
"bicycle_type_ids"=>["1",
"2"],
"logo_id"=>"",
"teaser_image_id"=>"",
"splash_image_id"=>""},
"id"=>"2",
"locale"=>:en}
I've been trying to figure this out and just keep hitting the same brick wall, so any help would be greatly appreciated!
Here's my code. Let me know if anything else would help.
Brands Controller
module Refinery
module Brands
module Admin
class BrandsController < ::Refinery::AdminController
crudify :'refinery/brands/brand',
:xhr_paging => true
end
end
end
end
Brands Model
module Refinery
module Brands
class Brand < Refinery::Core::BaseModel
self.table_name = 'refinery_brands'
attr_accessible :title, :teaser, :splash, :details, :introduction, :blockquote, :logo_id, :teaser_image_id, :splash_image_id, :position, :bicycle_type_ids
translates :title, :teaser, :splash, :details, :introduction, :blockquote
class Translation
attr_accessible :locale
end
validates :title, :presence => true, :uniqueness => true
belongs_to :logo, :class_name => '::Refinery::Image'
belongs_to :teaser_image, :class_name => '::Refinery::Image'
belongs_to :splash_image, :class_name => '::Refinery::Image'
has_and_belongs_to_many :bicycle_types
end
end
end
Bicycle Types Model
module Refinery
module BicycleTypes
class BicycleType < Refinery::Core::BaseModel
self.table_name = 'refinery_bicycle_types'
attr_accessible :title, :position
translates :title
class Translation
attr_accessible :locale
end
validates :title, :presence => true, :uniqueness => true
has_and_belongs_to_many :brands
accepts_nested_attributes_for :brands
end
end
end
Migration
class AddRefineryBicycleTypesBrands < ActiveRecord::Migration
def change
create_table :bicycle_types_brands, :id => false do |t|
t.references :bicycle_type
t.references :brand
end
add_index :bicycle_types_brands, [:bicycle_type_id, :brand_id], :unique => true
end
end
Form Partial (at least the part where I'm building my checkboxes)
<div class="field">
<%= f.label :bicycle_types %>
<% Refinery::BicycleTypes::BicycleType.order(:title).each do |bicycle_type| %>
<label class="checkbox">
<%= check_box_tag "#{f.object_name}[bicycle_type_ids][]", bicycle_type.id, f.object.bicycle_types %>
<%= bicycle_type.title %>
</label>
<% end %>
</div>
If the rest of the partial would be useful, or anything else for that matter, please let me know. Any help would be greatly appreciated!
you must specify the full class name:
has_and_belongs_to_many :bicycle_types, :class_name => "Refinery::BicycleTypes::BicycleType"
This is not your case but if you want to call the join table in a 'refinery style' (i.e refinery_bicycle_types_brands), you must also declare the join table:
has_and_belongs_to_many :bicycle_types, :join_table => :refinery_bicycle_types_brands, :class_name => "Refinery::BicycleTypes::BicycleType"
Bye

How to save embedded classes in mongoid?

I am using Rails 3 with mongoid 2. I have a mongoid class forum, which embeds_many topics.
Topics embeds_many forumposts
When I try to save a forumpost doing the following in my controller...
#forum = Forum.find(params[:forum_id])
#forum.topics.find(params[:topic_id]).forumposts.build(:topic_id => params[:forumpost][:topic_id], :content => params[:forumpost][:content], :user_id => current_user.id,:posted_at => Time.now, :created_at => Time.now, :updated_at => Time.now)
if #forum.save
On save I get...
undefined method `each' for 2012-11-14 23:15:39 UTC:Time
Why am I getting that error?
My forumpost class is as follows...
class Forumpost
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Paranoia
field :content, type: String
field :topic_id, type: String
field :user_id, type: String
field :posted_at, type: DateTime
attr_accessible :content, :topic_id, :user_id, :posted_at, :created_at, :updated_at
validates :content, presence: true
validates :topic_id, presence: true
validates :user_id, presence: true
belongs_to :topic
belongs_to :user
end
There is alot wrong/wierd with your example code, so lets see if we can start at the start:
You say forum embeds many topics, which embeds many posts. But your model is using a belongs_to association. Belongs_to is used for references which are different than embedded documents. If your Topic model has this:
class Topic
...
embeds_many :forumposts
...
end
Then your Forumpost model should have this:
class Forumpost
...
embedded_in :topic
...
end
Read up on references vs embedded documents here: http://mongoid.org/en/mongoid/docs/relations.html
Next point, You don't need to put :topic_id into the forumpost since you are building it off the topic.
Next point, don't save the forum, save the forumpost. And instead of doing a build followed by a save, try just doing it as a create in one go.
Next point, instead of setting user_id => current_user.id, try setting user => current_user. This is the magic that the belongs_to association provides... its cleaner and avoids messing around with IDs.
Next point, why do you need both created_at (supplied by Mongoid::Timestamps) and posted_at ?
Last point, you shouldn't need to set the timestamps, they should be set automatically when created/updated (unless for some reason you actually need posted_at).
Try something more like this:
#forum = Forum.find(params[:forum_id])
#topic = #forum.topics.find(params[:topic_id])
if #topic.forumposts.create(:content => params[:forumpost][:content], :user => current_user)
#handle the success case
else
#handle the error case
end

Is there an easier way of creating/choosing related data with ActiveAdmin?

Imagine I have the following models:
class Translation < ActiveRecord::Base
has_many :localizations
end
class Localization < ActiveRecord::Base
belongs_to :translation
end
If I do this in ActiveAdmin:
ActiveAdmin.register Localization do
form do |f|
f.input :word
f.input :content
end
end
The association for word will only allow me to choose from existing words. However, I'd like to have the option of creating a new word on the fly. I thought it may be useful to accept nested attributes in the localization model ( but then, I will only have the option of creating a Word, not selecting from existing ones ). How can I solve this problem?
I think you can try using virtual attribute for this
Example(not tested)
class Localization < ActiveRecord::Base
attr_accessor :new_word #virtual attribute
attr_accessible :word_id, :content, :new_word
belongs_to :translation
before_save do
unless #new_word.blank?
self.word = Word.create({:name => #new_word})
end
end
end
The main idea is to create and store new Word instance before saving localization and use it instead of word_id from drop-down.
ActiveAdmin.register Localization do
form do |f|
f.input :word
f.input :content
f.input :new_word, :as => :string
end
end
There is great rails-cast about virtual attributes http://railscasts.com/episodes/167-more-on-virtual-attributes

Using class variable

Beginner here, learning ruby on rails by jumping into a project. This question is probably pure ruby and has nothing to do with rails. I also want to note that I'm using Active_Admin.
I have the following 2 classes: Owner and Phone.
class Owner < ActiveRecord::Base
attr_accessible :email, :password,
has_many :phones
end
class Phone < ActiveRecord::Base
attr_accessible :owner_id :model
belongs_to :owner
end
How would I go accessing the owners email from within the phones model, for example:
form do |f|
f.inputs "Phone Details" do
f.input :model
f.input :owner_id # This is where I want the email, not the owners id.
end
f.buttons
end
It looks like I should review the pickaxe book and refine my ruby before jumping into rails.
Thanks
to have both the owner and the phone in one form, your form should look something like this:
form_for #phone do |phone_form|
phone_form.label :model
phone_form.text_field :model
fields_for #phone.owner do |owner_fields|
owner_fields.label :email
owner_fields.text_field :email
If you use this method, make sure you can update the Owner from the Phone model by setting accepts_nested_attributes_for :owner on you Phone model.
In this case you should use nested form. Usage of nested form is explained very well in this railscast.

rspec validates_presence_of polymorphic attributes ruby on rails

I am writing an rspec for an address model that has a polymorphic attribute called :addressable. I am using factory girl for testing.
This model has no controller because I do not wish to create a standalone address but that doesnt stop the rspec from creating a standalone address. My model, factory and rspec are
class Address < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
belongs_to :state
attr_accessible :street, :city, :state_id, :zip
validates_presence_of :street, :city, :zip, :state
validates_associated :state
end
Factory.define :address do |address|
address.street "1234 Any st"
address.city "Any City"
address.zip "90001"
address.association :state
end
describe Address do
before(:each) do
state = Factory(:state)
#attr = {:street => "1234 Any St", :city => "Any City", :zip => "Any Zip", :state_id => state.id}
end
it "should create a new address given valid attributes" do
Address.create!(#attr).valid?.should be_true
end
end
This rspec test will create an address with addressable_id and addressable_type of NULL and NULL but if I create from any other model, lets say a users model or a store model it will put in the correct data. So what I'm trying to figure out and research, unsuccessfully, is how do you validate_presence_of a polymorphic attribute and test it through a factory.
Sorry for being long winded but I havent been able to find a solution for this in the last couple of hours and I'm starting to consider I might be approaching this the wrong way.
I don't see anything in your spec that associates the address with an addressable. You are creating an address, but it's just out in space -- what is it connected to? NULL for addressable_id and addressable_type seems correct.

Resources