sunspot searchable include not loading has_and_belongs_to_many association - ruby-on-rails-3

in the following Sunspot Rails scenario the has_and_belongs_to_many association does not get loaded despite of the include directive:
has_and_belongs_to_many :predecessors, :join_table => 'next_phrases', :class_name => "Phrase", :foreign_key => 'next_id', :association_foreign_key => 'previous_id'
searchable :include =>[:predecessors] do
integer :predecessor_ids, :multiple => true,:references => Phrase
end
are we doing anything wrong or is that a bug?
it does work if we call self.association(:predecessors).reload by hand

it might have something to do with the fact that predecessor_ids is an internal field of the type array. it works if the name is changed to integer :predecessors.

Related

activeadmin habtm better example for uniqueness case

Am able to manage habtm as per follow, and I wanted a better way for this
I have habtm between User and Tag on Rails 3, aa 0.5.1
Tag name is uniq
f.input :tags, :label => 'Assign existing tag'
# this above allows to select from existing tags, but cannot allow to create one
f.has_many :tags, :label => 'Add new tags, modify existings' do |ff|
ff.input :name
ff.input :_destroy, :as => :boolean
end
# this above allows to create new one but not allow to specify existing one
# if we specify existing one, uniqueness wont let create this one, neither existing get used
# and throws validation error
any hints?
Adding my models
class User < ActiveRecord::Base
has_and_belongs_to_many :tags
scope :tagged_with, lambda {|tags| joins(:tags).where("tags.name" => tags)}
accepts_nested_attributes_for :tags, :allow_destroy => true
end
class Tag < ActiveRecord::Base
has_and_belongs_to_many :users
validates :name, :uniqueness => { :case_sensitive => false }
end
Try this,
f.label => 'Assign existing tag'
f.select :tags, Tag.all.map{|t| [t.tag_name, t.id]}, {:prompt => "Select Tag name" }
this above allows to select from existing tags, don't have option to create one
For the Second thing add this line in the model,
validates :tags, :uniqueness => {:scope => :tag_name}
here the :tag_name is your name of the fieldname. This throw an error if the tag name already exists when you create a duplicate.
It's just an idea as per your question. This won't be your exact answer because your specification is not enough to give you the exact answer.

How to validate uniqueness of nested models in the scope of their parent model in Rails 3.2?

Here is an example of my problem.
I have a 'Room' model:
class Room < ActiveRecord::Base
has_many :items, :inverse_of => :room
accepts_nested_attributes_for :items
end
And I have an 'Item' model:
class Item < ActiveRecord::Base
belongs_to :room, :inverse_of => :items
validates :some_attr, :uniqueness => { :scope => :room}
end
I want to validate the uniqueness of the :some_attr attribute of all the Items which belongs to a certain room.
When I try to validate the items, I get this error:
TypeError (Cannot visit Room)
I cannot set the scope of the validation to be :room_id since the items are not saved yet so the id is nil. I also want to prevent using custom validators in the 'Room' model.
Is there any clean way to do it in Rails? I also wonder if I set the :inverse_of option correctly...
I don't see anything wrong with how you're using inverse_of.
As for the problem, in a similar situation I ended up forcing a uniqueness constraint in a migration, like so
add_index :items, [ :room_id, :some_attr ], :unique => true
This is in addition to the AR-level validation
validates_uniqueness_of :some_attr, :scope => :room_id
(I'm not sure if it's valid to use the association name as a scope, won't the DB adapter raise an exception when trying to refer to the non-existent room column in a query?)

has_many :through :uniq relationship needs to collect everything from the through table

Here's a problem that is kinda hard to explain. So here's an example. Let's say I have this in the model:
has_many :things,
:through => :relationships,
:source => :thing
I need to get a list of things and whatever data I have on the relationships table. Let's say it's 'relationships.name'. We can do it like this:
has_many :things,
:through => :relationships,
:source => :thing,
:select => 'things.*, relationships.name as rel_name'
So if there are 2 relationships present I'll get 2 objects back:
#<Thing id: 1, rel_name: "foo">
#<Thing id: 1, rel_name: "bar">
If we cram :unique => true or adjust select to use DISTINCT we'll get unique objects, but data about one of the relationships will be gone. What I really want are unique things with all different relationship names collected into an accessor:
#<Thing id: 1, rel_names: ["foo", "bar"] >
Is there some dark SQL magic I'm not aware of that can do this? It's important for me to preserve the scope, so I can't just cycle through result set to collect that data.
Thanks
MySQL has the GROUP_CONCAT() method for this sort of thing:
has_many :things,
:through => :relationships,
:source => :thing,
:select => 'things.*, GROUP_CONCAT(relationships.name as rel_name)'
using GROUP_CONCAT on MySQL:
class MyModel < ActiveRecord::Base
attr_accessor :rel_names
has_many :things,
:through => :relationships,
:source => :thing,
:select => 'things.*, GROUP_CONCAT(DISTINCT relationships.name SEPARATOR ";;") as rel_names'
# .. your code ..
def rel_names
#rel_names.present? ? #rel_names.split(';;') : []
end
end

Setting up a polymorphic has_many :through relationship

rails g model Article name:string
rails g model Category name:string
rails g model Tag name:string taggable_id:integer taggable_type:string category_id:integer
I have created my models as shown in the preceding code. Articles will be one of many models which can have tags. The category model will contain all categories which may be assigned. The tag model will be a polymorphic join-table which represents tagged relationships.
class Article < ActiveRecord::Base
has_many :tags, :as => :taggable
has_many :categories, :through => :taggable
end
class Category < ActiveRecord::Base
has_many :tags, :as => :taggable
has_many :articles, :through => :taggable
end
class Tag < ActiveRecord::Base
belongs_to :taggable, :polymorphic => true
belongs_to :category
end
I can't seem to get this to work, I can do it non polymorphic, but I must have something wrong with the polymorphic part. Any ideas?
Edit: Still not getting this right:
class Article < ActiveRecord::Base
has_many :taggables, :as => :tag
has_many :categories, :through => :taggables, :source => :tag, :source_type => "Article"
end
class Category < ActiveRecord::Base
has_many :taggables, :as => :tag
has_many :articles, :through => :taggables, :source => :tag, :source_type => "Article"
end
class Tag < ActiveRecord::Base
belongs_to :taggable, :polymorphic => true
belongs_to :category
end
To create a polymorphic has_many :through, you must first create your models. We will use'Article,' 'Category,' and 'Tag' where 'Tag' is the join-model and Article is one of many objects which can be "tagged" with a category.
First you create your 'Article' and 'Category' models. These are basic models which do not need any special attention, just yet:
rails g model Article name:string
rails g model Category name:string
Now, we will create our polymorphic join-table:
rails g model Tag taggable_id:integer taggable_type:string category_id:integer
The join-table joins together two tables, or in our case one table to many others via polymorphic behavior. It does this by storing the ID from two separate tables. This creates a link. Our 'Category' table will always be a 'Category' so we include 'category_id.' The tables it links to vary, so we add an item 'taggable_id' which holds the id of any taggable item. Then, we use 'taggable_type' to complete the link allowing the link to know what it is linked to, such as an article.
Now, we need to set up our models:
class Article < ActiveRecord::Base
has_many :tags, :as => :taggable, :dependent => :destroy
has_many :categories, :through => :tags
end
class Category < ActiveRecord::Base
has_many :tags, :dependent => :destroy
has_many :articles, :through => :tags, :source => :taggable, :source_type => 'Article'
end
class Tag < ActiveRecord::Base
belongs_to :taggable, :polymorphic => true
belongs_to :category
end
After this, setup your database using:
rake db:migrate
That's it! Now, you can setup your database with real data:
Category.create :name => "Food"
Article.create :name => "Picking the right restaurant."
Article.create :name => "The perfect cherry pie!"
Article.create :name => "Foods to avoid when in a hurry!"
Category.create :name => "Kitchen"
Article.create :name => "The buyers guide to great refrigeration units."
Article.create :name => "The best stove for your money."
Category.create :name => "Beverages"
Article.create :name => "How to: Make your own soda."
Article.create :name => "How to: Fermenting fruit."
Now you have a few categories and various articles. They are not categorized using tags, however. So, we will need to do that:
a = Tag.new
a.taggable = Article.find_by_name("Picking the right restaurant.")
a.category = Category.find_by_name("Food")
a.save
You could then repeat this for each, this will link your categories and articles. After doing this you will be able to access each article's categories and each categorie's articles:
Article.first.categories
Category.first.articles
Notes:
1)Whenever you want to delete an item that is linked by a link-model make sure to use "destroy." When you destroy a linked object, it will also destroy the link. This ensures that there are no bad or dead links. This is why we use ':dependent => :destroy'
2)When setting up our 'Article' model, which is one our 'taggable' models, it must be linked using :as. Since in the preceeding example we used 'taggable_type' and 'taggable_id' we use :as => :taggable. This helps rails know how to store the values in the database.
3)When linking categories to articles, we use:
has_many :articles, :through => :tags, :source => :taggable, :source_type => 'Article'
This tells the category model that it should have many :articles through :tags. The source is :taggable, for the same reason as above. The source-type is "Article" because a model will automatically set taggable_type to its own name.
You simply cannot make the join table polymorphic, at least Rails does not support this out of the box. The solution is (taken from Obie's Rails 3 way):
If you really need it, has_many :through is possible with polymorphic associations, but only by specifying exactly what type of polymorphic associations you want. To do so you must use the :source_type option. In most cases you will have to use the :source option, since the association name will not match the interface name used for the polymorphic association:
class User < ActiveRecord::Base
has_many :comments
has_many :commented_timesheets, :through => :comments, :source => :commentable,
:source_type => "Timesheet"
has_many :commented_billable_weeks, :through => :comments, :source => :commentable,
:source_type => "BillableWeek"
It's verbose and the whole scheme loses its elegance if you go this route, but it works:
User.first.commented_timesheets
I hope I helped!

MongoID, embedding a document in multiple documents

I have a model Address like following
class Address
include Mongoid::Document
field :line1
field :city
# more fields like this
embedded_in :user, :inverse_of => :permanent_address
embedded_in :user, :inverse_of => :current_address
embedded_in :college, :inverse_of => :address
end
There are models College and User which embed address
class College
include Mongoid::Document
references_many :users
embeds_one :address
# some fields and more code
end
class User
include Mongoid::Document
referenced_in :college, :inverse_of => :users
embeds_one :permanent_address, :class_name => "Address"
embeds_one :current_address, :class_name => "Address"
# fields and more code
end
I am getting some problems with the above setup. I am using single form to ask for current and permanent address along with some more information, but only current_address is getting saved and that too with the data I populate in permanent_address.
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"KdOLvzmKyX341SSTc1SoUG6QIP9NplbAwkQkcx8cgdk=",
"user"=> {
"personal_info_attributes"=>{...},
"nick_names_attributes"=>{...},
"current_address_attributes"=>{
"line1"=>"",
"area"=>"",
"country"=>"USA",
"postal_code"=>"sd",
"city"=>"",
"state"=>"",
"landmark"=>"",
"id"=>"4d891397932ecf36a4000064"
},
"permanent_address_attributes"=>{
"line1"=>"",
"area"=>"asd",
"country"=>"india",
"postal_code"=>"",
"city"=>"",
"state"=>"",
"landmark"=>""
},
"commit"=>"Submit", "id"=>"4d8903d6932ecf32cf000001"}
MONGODB alma_connect['users'].find({:_id=>BSON::ObjectId('4d8903d6932ecf32cf000001')})
MONGODB alma_connect['users'].update({"_id"=>BSON::ObjectId('4d8903d6932ecf32cf000001')},
{"$set"=>{
"current_address"=>{
"line1"=>"",
"area"=>"asd",
"country"=>"india",
"postal_code"=>"",
"city"=>"",
"state"=>"",
"landmark"=>"",
"_id"=>BSON::ObjectId('4d8916e9932ecf381f000005')}}})
I am not sure if this is something I am doing wrong here or there is some other problem. I am using Rails 3.0.4 and MongoID 2.0.0.rc.7
Update:
I upgraded to mongoid 2.0.1 and changed my user to include inverse of options in address.
class User
include Mongoid::Document
referenced_in :college, :inverse_of => :users
embeds_one :permanent_address, :class_name => "Address", :inverse_of => :permanent_address
embeds_one :current_address, :class_name => "Address", :inverse_of => :current_address
# fields and more code
end
I know the inverse of names doesn't make sense, but the main point here is just to make them different or if you have good names for relations in your embedded class(like :current_user, :permanent_user), you should use that for inverse of.
Looks good to me. I've a similar setup and it works as expected.