HasFinder is an extension to ActiveRecord that makes it easier than ever to create custom find and count queries.
Let’s start with an example. Suppose you have an Article model; some articles are published, some are popular. Let’s declare finders for each of these notions. You may be tempted to write something like the following:
class Article < ActiveRecord::Base
def self.published
find(:all, :conditions => {:published => true})
end
def self.popular
...
end
...
end
But there are serious limitations to this approach. How do you find articles that are BOTH popular and published? How can you easily paginate published articles?
HasFinder Features
Let’s define the equivalent finders using my new plugin, has_finder:
class Article < ActiveRecord::Base
has_finder :published, :conditions => {:published => true}
has_finder :popular, :conditions => ...
end
Query Composition
Now, you can elegantly compose queries:
Article.published.popular
This will return all articles that are both popular and published.
Calculations and Nested Finds
You can also easily paginate or call nested finders or do calculations:
Article.published.paginate(:page => 1)
Article.published.popular.count
Article.popular.find(:first)
Article.popular.find(:all, :conditions => {...})
Works with ActiveRecord has_many and has_many :through Associations
Furthermore, without any additional work, these finders will work with ActiveRecord associations.
class User
has_many :articles
end
user.articles.popular.find(:first)
user.articles.published.popular.average(:view_count)
Finders are extendable just like ActiveRecord Associations
class Article
has_finder :unpublished :conditions => {:published => false} do
def published_all
find(:all).map(&:publish)
end
end
end
Alternatively, you can use the :extend options:
class Article
has_finder :unpublished, :conditions => ..., :extend => MyExtensionModule
end
Finders behave just like ActiveRecord Associations
For example, you can call #reload:
Article.published.popular.reload
Finders can take parameters
class Car
has_finder :colored, lambda {|color| { :conditions => {:color => color} } }
end
Car.colored('red').paginate(:page => 1)
What makes HasFinder better than alternatives like scope_out and scoped_proxy?
There are already two plugins similar to HasFinder: scope_out and scoped_proxy. Both of them are excellent. In fact, Scoped Proxy was the model for HasFinder. Unfortunately, neither plugin provided all of the features I desired. Scope-Out lacks on-the-fly composition, a nice way to call a nested find, or the ability to do arbitrary calculations. Scoped Proxy is great, but it doesn’t work with regular ActiveRecord Associations, it is not extendable like ActiveRecord associations, and it doesn’t behave exactly like a regular ActiveRecord Association. Neither of them work out of the box with will_paginate. For all of these reasons and more, I rolled my own. It’s now available as a gem.
Installation
% gem install has_finder
Usage
In environment.rb:
gem 'has_finder'
require 'has_finder'
See the examples above for usage.
I’m trying to dynamically add has_finder methods to model classes. As my first exploration I tried the following in a model class:
content_columns.select {|c| c.type == :string}.each do |column|
has_finder column.name.to_sym,
lambda {|param| { :conditions => {column.name.to_sym => param} } }
end
Unfortunately this isn’t working. I’m seeing the following error many times when I true to use one of these finders:
/path/to/my/mode_model.rb:42: warning: multiple values for a block parameter (0 for 1)
from /path/to/my/rails_root/vendor/plugins/has_finder/lib/has_finder/has_finder.rb:55
Any idea how I might be able to pull this off?
Thanks.
February 8, 2008 at 8:30 pm
Hello there,
has anyone used has_finder successfully with has_many_polymorphs associations?
Basically I have an user model which has many items (which can be of type :a, :b and :c) and for example I want to get all UserItems which have been created yesterday (finding within the hmp user.items associations). I am kinda confused atm because it isn’t working as expected :-/
_j
February 24, 2008 at 1:16 pm
Markdown obviously messes with the _’es ;)
Anyway – what I forgot to add was the setup: I have one User model, one UserItem model and several other models A, B and C. UserItem is the join model for the hmp associations. I placed e.g. this finder in there:
has_finder :created_today, :conditions => ['created_at > ?', Date.yesterday]
Now when I fetch an User u and do a u.items.created_today, I get a big, bad exception:
ActiveRecord::StatementInvalid: Mysql::Error: Column ‘created_at’ in where clause is ambiguous: …. :-/
A, B and C have all the typical 2 rails timestamp columns and so do the useritems.
Any Idea what’s wrong here?
February 24, 2008 at 1:29 pm
Jorg,
HMP scares me – I’ve used it before and with no good effect. It looks like a simple workaround to your problem would be:
has_finder :created_today, :conditions => ['users.created_at > ?', Date.yesterday]
Note the prefix on the created_at column. Also, bear in mind that doing Date.yesterday is really dangerous as the statement gets evalled at class-eval time, meaning if your code is long-running, yesterday may be 5 days ago, etc.
Two workarounds for that are: 1) use the lambda form, 2) put the date in the sql clause, not using bind (the question-mark).
February 24, 2008 at 6:04 pm
Hi Nick,
I found a bug with finders that only do an “order by”. For example:
hasfinder :popular, :order => ‘hits desc’
hasfinder :alphabetical, :order => ‘name asc’
Topic.popular.alphabetical would only do “order by hits desc” and not “order by hits desc, name asc”.
You’ve created a wonderful gem. Any update on if and when it will be available as a plugin or can we hope to see this in the official Rails release soon?
Regards,
Jason
March 3, 2008 at 2:35 am
Hi again! First, I have to say I am really digging this gem, man! This is exactly what Rails needed.
I found another small bug – when I do something like this:
forum.topics.popular
The generated SQL checks forum_id twice:
SELECT * FROM `topics` WHERE (topics.forum_id = 13) AND (topics.forum_id = 13) ORDER BY posts_count desc
My finder is the following:
has_finder :popular, :order => ‘posts_count desc’
March 3, 2008 at 6:31 am
I think that rails core team should consider has_finder as part of AR. It’s useful thing like associations. I hope that some day it becomes part of AR.
March 16, 2008 at 2:53 pm
Thank you for releasing has_finder. It’s a pleasure to use.
I want to use it in conjunction Geokit. Geokit adds :origin and :within options to finders. In a has_finder, it does not recognise these options.
Can anyone help at all?
March 16, 2008 at 9:07 pm
I encountered a “superclass mismatch for class Annotation” when trying to use with rails 2.0.2.
How to fix that?
March 17, 2008 at 6:37 pm
My solution is ugly -but it works.
You have to remove the spec directory from plugin’s source.
March 18, 2008 at 9:09 am
And there is second way.
Just install it as a gem. (instructions here:
http://pivotalrb.rubyforge.org/svn/has_finder/trunk/has_finder/README.txt)
In such way it has no problems with rake.
March 18, 2008 at 9:25 am
I had the same problem jochen. I also removed the spec directory!
I want to chain a number of has_finders together. Some of these finders might have nil as parameter, in which case I’d like it to be ignored. Is there any way of doing this?
i.e.
Shoes.of_size(10).of_colour(nil).under(40)
I tried messing with the lamda but didn’t get very far.
March 18, 2008 at 3:45 pm
How does this plugin play along with paginating_find?
I’m trying to do something like:
has_finder :paged, :page => {:size => 100, :auto => true}, :order => :id
Which should potentially allow:
User.active.paged
March 25, 2008 at 2:57 pm
Am I correct in assuming has_finder will not work with HABTM associations? I’ve tried it and it doesn’t produce the correct results. Just wondering if I’m doing something wrong or its just not supported.
Other than that, been loving the plugin, thanks!
April 11, 2008 at 6:47 pm
Hi,
nice gem!
I wanted to point another use which was very helpful for me.
I needed to compose several OPTIONAL queries… Say your Person#controller accepts params[:search] and params[:ver] (with a boolean field), and you can call it with either or both of params. In the controller I would like just to call:
Person.search(params[:search]).verification(params[:ver])
and I wanted it to work with no (eg. give me all Person), one or the above two params options.
I managed to do this by defining the has_finder like:
has_finder :search, lambda {|name|
{:conditions => name.nil? ? nil :
["name LIKE ?", name+"%"] }
}
has_finder :ver, lambda {|v|
{:conditions => v.nil? ? nil : :conditions => {:verification = v} }
}
Bye,
Z
April 14, 2008 at 7:13 pm
Hi nick,
great job!
but i found that has_finder does not work with polymorphic :has_many.
here is the test code.
class Membership < ActiveRecord::Base
belongs_to :joinable, :polymorphic => true
has_finder :accepted, :conditions => { :accepted => true }
end
class Group < ActiveRecord::Base
has_many :memberships, :as => :joinable
end
the snippet
Group.find(:first).memberships
produces the sql
SELECT * FROM `memberships` WHERE (memberships.joinable_id = 1 AND memberships.joinable_type = 'Group')
while
Group.find(:first).memberships.accepted
only produces the sql
SELECT * FROM `memberships` WHERE (accepted_at is not NULL)
am i missing something?
April 28, 2008 at 6:17 am
Hi nick,
great job!
but i found that has_finder does not work with polymorphic :has_many.
here is the test code.
the snippet
Group.find(:first).memberships
produces the sql
while
Group.find(:first).memberships.accepted
only produces the sql
am i missing something?
April 28, 2008 at 6:21 am
Hi there,
Does has_finder cache the result of searches like usual AssociationProxies do?
class Task < AR
has_finder :resolved, :condititions => { :resolved => true }
end
Task.resolved
Task.resolved
produces two SQL quiries!!!
April 28, 2008 at 9:39 am
UVSoft:
It does cache results. `x = Task.resolved` has not yet hit the database. `x.collect` will hit the db one time. `x.collect` again will not hit the database. You do *not* want to cache `Task.resolved` as it’s effectively a global variable that will persist across http requests.
April 28, 2008 at 5:01 pm
Quick question, is there a reason has_finder/named scope ignores the :limit option?
class Product
named_scope :most_ordered, :condition => {:status => ONLINE}, :order => 'ordered_count DESC'
end
# Should return the top ten most ordered products but doesn't..
Product.most_ordered(:limit => 10)
At the moment, I’m using a lamda to pass in the limit and get around this, but this doesn’t feel right:
named_scope :most_ordered, lambda { |l| limit = l ? { :limit => l } : {}
{:conditions => {:status => ONLINE}, :order => 'ordered_count DESC'}.merge(limit) }
May 14, 2008 at 9:47 pm
Hi Nick.
Not too sure if this awesome plugin is still maintained (as it is in Rails 2.x). I had hoped it would be on GitHub so that I could try my first fork and pull request. Alas, no luck…
Just a quick post here in the hope this would benefit anyone else still not on Rails 2.x.
I have a parametrised has_finder as follows:
has_finder :most_popular, lambda { |limit| limit = 5 if limit.blank?
{:conditions => ['id in (select photo_id from categories_photos where id = photo_id) and views_count > 0 and approved = ?',true],
:order => ‘created_on DESC’, :limit => limit}
}
Which works well. Except when doing the following:
my_object.most_popular.length
A correct result is returned (ie 5) but with the following warning:
multiple values for a block parameter (0 for 1) from
/home/nazar/Rails/photos.git/vendor/plugins/has_finder/lib/has_finder/has_finder.rb
I’ve tweaked the complaining module (lib/has_finder/has_finder.rb in module ClassMethods
def has_finder(name, options = {}, &block)
finders[name] = lambda do |parent_finder, *args|
FinderProxy.new(parent_finder, case options
when Hash
options
when Proc
if args.length > 0
options.call(*args)
else
options.call(nil)
end
end, &block)
end
meta_def(name) do |*args|
finders[name].call(self, *args)
end
end
Hope this is:
a) correct
b) helps anybody else who stumbles on this
Many thanks for one my most favourite plugins! :)
June 23, 2008 at 8:23 pm
For those asking about using geokit with has_finder/named_scope, I got this to work:
named_scope :within, lambda{|o, d|
origin = o
distance_sql = self.distance_sql(origin)
within = d
{:select => “*, #{distance_sql} as distance”,
:conditions => “#{distance_sql} < = #{within}",
:order => ‘distance asc’}}
September 4, 2008 at 7:56 pm
Very nice!
Maybe make available as a plugin instead?
Also – why “has_finder” – why not just an explicit “finder”?
December 12, 2007 at 11:50 pm
Awesome. I wrote something to enable the same call syntax the other day, but this is much better. I second the vote for a plugin!
December 12, 2007 at 11:50 pm
Josh/Ryan — thanks for the feedback. I’ll package this as a plugin soon. As for calling the method “finder” vs. “has_finder” — I’m OK with both. Let’s have a vote!
December 12, 2007 at 11:50 pm
Really sweet!
But isn’t with_scope going to be a protected method? Implications on this?
Trying something like Page.published.find(params[:id])) in edge and it fails, something like @page.published.children.find(:all) works fine though..
December 12, 2007 at 11:50 pm
Joel — I just updated the gem to use
send :with_scope. I can’t seem to get rake to run on a freshly generated edge rails app, so I’m unsure whether this will fix the defect or not. Let me know!December 12, 2007 at 11:50 pm
That seems to do it. Much obliged =)
(Did you try gem update –system; gem update rake; for edge rails?)
December 12, 2007 at 11:50 pm
Hi,
For some reason there is a bug when using with scope. For example
User.scoped_by_site(1) { User.superusers }
and
User.scoped_by_site(1) { User.superusers.find(:all) }
for the first example, it doesn’t respect the scope, for the second it does.
Any thoughts?
December 12, 2007 at 11:50 pm
Cyx: That kind of usage is impossible to support, unfortunately. It’s difficult to explain why that doesn’t work, but let me try:
User.superusers returns a proxy object, not an array. What you’re doing:
is more or less equivalent to just
Since the more complex expression just returns the proxy object. The withscope only “lasts” as long as the block being passed to it; it’s destroyed as soon as the block returns. In your first example, you’ll only effect the find after scopedbysite returns (e.g., by calling #each or #find), at which point the withscope is long gone.
This fact is, by far, the most complex part of how hasfinder works. If you want an object to encapsulate a scope (which is more or less what hasfinder does), composition is only possible if the objects no how to chain themselves together, such that method invocation leads to nested with_scopes. Look at the source code for details. In any case, I recommend you do the following:
and then you should be OK.
December 12, 2007 at 11:50 pm
great idea! vote for plugin too :).
for STI it doesn’t work. for now i put has_finder’s definition in a module and included it in tables-children. other way i’ve got that:
The error occurred while evaluating nil.call
from …/gems/has_finder-0.1.2/lib/has_finder/has_finder.rb:59:in ‘published’
December 12, 2007 at 11:50 pm
One problem I’m having with nested scopes:
Article.published.popular executes two queries, one to get published and another to get published AND popular AND published.
SELECT * FROM articles WHERE (published = 1)
SELECT * FROM articles WHERE (( ( published = 1 ) AND ( popular = 1 ) ) AND ( published = 1 ))
December 12, 2007 at 11:50 pm
I was hacking around earlier and ended up implementing a half-baked version of this that doesn’t involve the use of AssociationProxies:
http://pastie.caboo.se/95207
It’s definitely under-powered (I’m using has_finder instead), but folks might find the approach interesting.
December 12, 2007 at 11:50 pm
I was hacking around earlier and ended up implementing a half-baked version of this that doesn’t involve the use of AssociationProxies:
http://pastie.caboo.se/95207
It’s definitely under-powered (I’m using has_finder instead), but folks might find the approach interesting.
December 12, 2007 at 11:50 pm
macovsky – i’ll fix this bug and release a new version in the next couple of days.
grant – i’ll see if I can reproduce this behavior.
December 12, 2007 at 11:50 pm
Great! Since I was playing around with scopeout and scopedproxy, I always wanted to somehow combine the advantages of both plugins. I didn’t try hasfinder yet, but it looks like it does exactly what I am searching for, so +1 for a hasfinder plugin :-)
December 12, 2007 at 11:50 pm
macovsky/grant – both issues should be fixed and are now available as has_finder 0.1.3.
December 12, 2007 at 11:50 pm
Hi, thanks again for a excellent piece of software..
Have you thought about calculations? eg. Order.completed.sum(:amount) ect. (That maybe out of scope for has_finder though)
Just checking if you are implementing it before I try a stab at it myself..
On another note, it’s busted in edge again =)
I’m getting
vendor/rails/activerecord/lib/activerecord/base.rb:1277:in
method_missing_without_paginate': undefined methodhasfinder’ for # (NoMethodError)lots of stuff going on in edge now apparantly.
I think it has to do with how you include the HasManyAssociations, changing from just using include to doing a class_eval seems to do it.
like so:
ActiveRecord::Base.send :include, HasFinder::ActiveRecord
module ActiveRecord::Associations
[HasManyAssociation, HasManyThroughAssociation].each do |klass|
klass.class_eval do
include HasFinder::HasManyAssociation
aliasmethodchain :methodmissing, :hasfinder
end
end
end
December 12, 2007 at 11:50 pm
whoops, busted rendering but you get the idea =)
December 12, 2007 at 11:50 pm
Joel — I’ll make those fixes later tonight… As for #sum, in theory they should be working (I thought they were already) since I thought with_scope affected calculations as well… I’ll double check that stuff.
December 12, 2007 at 11:50 pm
Joel — I fixed the issue with sum (was being delegated to the array rather than ActiveRecord). I could not reproduce your issue in edge (just tried with latest version right now), sorry!
Try 0.1.5 and let me know if it’s any better.
December 12, 2007 at 11:50 pm
two things. one, i’m unable to get hasfinder working. I get an error from ActiveRecord::Base:
“in’method_missing’:ArgumentError: no id given”
on the line that calls “super” at the end. not sure what’s going on there.
also…Is there any way to include has_finder finders directly on an association? so for instance:
User
– has_finder :active, :conditions = {:deactivated = false}
Group
has_many :memberships
has_many :members, :through = :memberships, :with_finder = :active
that would seem easier than having to always access @group.members.active
December 12, 2007 at 11:50 pm
Hi oliver:
There’s not yet planned support for things like:
hasmany … :withfinder => :active
Good idea though, so I’ll consider adding it.
I cannot reproduce the error you have with has_finder. I need more detail. Send me a full stack trace (nick @ pivotallabs.com), and any source code that you can… Something to do might be generate a new rails app, require the gem in your environment and write a few lines of code that fail… you can zip it up and send it all to me.
December 12, 2007 at 11:50 pm
Oliver, PS:
end
Not super-concise, but it gives you almost all that you want.
December 12, 2007 at 11:50 pm
Nick,
HasFinder is quite a gem (in many ways), but do you have it available in an svn repo so it can be installed as a plugin?
December 12, 2007 at 11:50 pm
brandon: source code is in rubyforge in the pivotalrb project. thanks for your interest!
December 12, 2007 at 11:50 pm
I want to install as script/plugin is it posible?
December 12, 2007 at 11:50 pm
I want to install as script/plugin is it posible?
December 12, 2007 at 11:50 pm
can you use associations in the conditional:
December 12, 2007 at 11:50 pm
can you use associations in the conditional:
December 12, 2007 at 11:50 pm
can you use associations in the conditional:
December 12, 2007 at 11:50 pm
@ those that were asking about using this as a plugin:
Install it as a gem, then copy the ‘has_finder-0.1.5′ from the ‘ruby/lib/ruby/gems/1.8/gems’ directory into ‘vendor/plugins’, and put:
require 'has_finder'into a new file named init.rb, inside that folder, then you dont need the two lines in your environment.rb file either.
I think you can also safely delete the config and test folders, and the ‘setup.rb’ file, as they are then redundant. Oh and don’t forget to restart the server (as I always do!)
A lot of gems can be ‘converted’ this way as they share the same basic structure as rails plugins.
And thanks nick, this is just what i’ve been looking for :)
December 12, 2007 at 11:50 pm
This plugin (gem) seems to have the same problem with :group option of AR.find method that scope_out suffers. Namely it does not seem to support it.
ex…
hasfinder :nonactive, :group => ‘login’
fails with…
ActionView::TemplateError (Unknown key(s): group) on line #10 of app/views/users/_index.rhtml:
/var/lib/gems/1.8/gems/activesupport-1.4.4/lib/activesupport/coreext/hash/keys.rb:48:in
assert_valid_keys'with_scope’/var/lib/gems/1.8/gems/activerecord-1.15.5/lib/active_record/base.rb:913:in
December 12, 2007 at 11:50 pm
FYI, a work around for the lack of :group support
ex…
hasfinder :nonactive, :select => ‘distinct …’
seems to work for me, but the :group option would be nice – as it’s a standard part of find method
December 12, 2007 at 11:50 pm
Mark — your technique should work.
Andy — unfortunately, I rely on
with_scope(as doesscope_out) and it does not supportgroup by. I can give you source code to makewith_scopesupportgroup_by, (it’s fairly straightforward), but I wouldn’t want to include it inhas_finderbecause of its potentially undesirable effect on the rest of the Rails app.December 12, 2007 at 11:50 pm
It would be good to get an access to SVN repo. I want to install this plugin using Piston (http://piston.rubyforge.org/). It is much better than copying Gem
December 12, 2007 at 11:50 pm
DEkart — http://pivotalrb.rubyforge.org/svn/hasfinder/trunk/hasfinder/
December 12, 2007 at 11:50 pm
I am currently using custom finders like this
class Barcode < ActiveRecord::Base
def self.findallbyclient(clientid)
self.findallbyclientid(clientid, :include => {:item => :itemtype}, :order => “item_types.name, items.name”)
end
end
I would like to replace it with this but how can I pass the session variable session[:client] to the has_finder method?
hasfinder :all, :conditions => {:clientid => session[:client]}, :include => {:item => :itemtype}, :order => “itemtypes.name, items.name”
December 12, 2007 at 11:50 pm
My underscores got stripped out of that post but you can still get the point.
December 12, 2007 at 11:50 pm
Chris — only the controller (and view) have access to the session (for better or worse). The easiest thing to do is pass in the client_id as a parameter to the finder, as you did in your
self.find_all_by...In the example you gave above, it doesn’t seem like you need your model to know about the session… But,
If you want the session available in your model layer, this is an obstacle totally unrelated to
has_finder. Use anaround_filterto set (and unset) a class variable on AR::Base or a thread-local variable that AR::Base has access to. Better yet,alias_method_chainperform_actionto do the same thing (this will ensure your session is available in your models in theafter_filtersthat happen after youraround_filter).Don’t let anyone give you a hard time about MVC. Dogma does not lead to good software design.
December 12, 2007 at 11:50 pm
Thanks, that works great for finding a collection of objects but when I try to find a single item for my show action, I get an method missing error. I think this is because has_finder is returning an array and my show action is treating it like an object.
hasfinder :one, lambda {|id, clientid| { :conditions => {:id => id, :clientid => clientid} } }
How can I write this to return a single object instead of an array of 1, or should I just use a custom method for finding one object instead of using has_finder?
December 12, 2007 at 11:50 pm
chris — has finder is not really designed for the “one” case. A simple, but clumsy, implementation might be something like the following:
December 12, 2007 at 11:50 pm
Thanks Nick, you’ve been so helpful. One more question. I have the following defined.
When I call Plan.active.business(session[:client]) I get nothing in the result list because the conditions are merged and the has finder for active is supplying the condition client_id = null because I didn’t pass it in the controller. To make it work I have to call Plan.active(session[:client]).business(session[:client]) and that works fine, I was just wondering if there was a prettier way to write it.
By the time I got to the end of writing this post, I have decided to myself that its better this way but still let me know what you think. I’m still considering using the around filter that you mentioned before because the way my app is designed, every query in every model requires the client_id.
December 12, 2007 at 11:50 pm
This is perfect, just in the nick of time.
Thanks!
December 12, 2007 at 11:50 pm
gem ‘has_finder’
= true
require ‘has_finder’
NoMethodError: undefined method ‘delegate’ for HasFinder::FinderProxy:Class
Eek, what’s going on?
December 12, 2007 at 11:50 pm
delegate is a method from activesupport. You must be requring ‘hasfinder’ too early in your environment file–assuming you’re using Rails. If you’re not using Rails, make sure to require has_finder after active record
December 12, 2007 at 11:50 pm
YOU ROCK. This works great!
December 12, 2007 at 11:50 pm
Daniel:
And voila:
December 12, 2007 at 11:50 pm
Haha, thanks! I ended up doing this before the reply:
Now I can refactor!
Thanks!
December 12, 2007 at 11:50 pm
Absolutely Great thing, thanks a lot, man!
I’ve noticed a bug when was using models in modules.
results in a ‘X is not missing constant Bar’ error.
The workaround for this is to use absolute name – ::Foo::Bar, instead of just Bar.
But it is possible that I did something wrong…
December 12, 2007 at 11:50 pm
Okay, we really need to package this as a plugin…
December 12, 2007 at 11:50 pm
Vlad — if you give me a full stack trace I will look into it in more detail. I know that using AR’s in modules in general can cause problems with associations like belongsto (at least it did with Rails 1.2.3), so it’s possible hasfinder is unrelated, not sure. But I’ll fix it if I can.
December 12, 2007 at 11:50 pm
Sure, here it is:
The call is like
To get the point what I’m trying to do: navigating kind of a graph, with multiple paths on the same vertices :)
December 12, 2007 at 11:50 pm
I thought I posted this already but I didn’t see the comment appear. I have realized that in rails, when you do a find(:all) statement inside of an association (has_many :somethings, :thought => :other_things do; def completed; find(:all, :conditions => {:completed => 1}); end;) it breaks the :uniq => true statement in the association. I’m able to fix this in my models when i define finders to narrow a search down by just adding a .uniq to the end of the statement (find(:all).uniq) .. is there any way to add this functionality to has_finders? I’d love to use this gem and make my finders much easier to use and read, but i NEED the uniq fix and can’t figure out how to do it myself with this gem. Any help?
December 14, 2007 at 9:31 am
After playing around in the source, I added .uniq to the find(:all) statement in the load_found private method and it now only returns unique results. This’ll do until an official fix is released.
December 14, 2007 at 10:26 am
Those looking for a plugin version can try this checkout into their plugins directory..
svn checkout http://pivotalrb.rubyforge.org/svn/has_finder/trunk/has_finder
January 26, 2008 at 1:29 am
Hi!,
I tried to use has_finder and has_many_polymorphs (tagging_extensions), but I get a strange behavior…
I have two taggable models, in one of them I’ve added a finder (using has_finder)… and in that model I can’t access the dynamic method added by tagging_extensions (tags for example). In the model where I haven’t added any finder I can access these methods without any problem.
For some reason, when I ask for the Tag model… this problem doesn’t happen anymore….
—– environment.rb
require 'tagging_extensions'
require 'has_finder'
Tag
The last line makes all work fine.
This model Tag, adds to my two models a lot of methods via :extend options in has_many_polymorphs… I think that is the reason why the problem doesn’t happen anymore.. but I think that is not the correct way for solving it..
Any ideas?
Thanks
January 30, 2008 at 1:23 pm
Finally found a scoping plugin that works with acts_as_tree out of the box. Thank you :)
January 31, 2008 at 12:56 pm
It seems that HasFinder overrides the model translating aspect of Globalize (an il8n plugin for Rails), at least in the case where one is using the default translation storage.
It’s a very nice system, otherwise!
January 31, 2008 at 1:47 pm
This is so great. One “problem” I found though, was that I’ve started using rails new partial renderthingie:
controller:
@posts = Post.a_has_finder_finder
view:
render :partial => @posts
This doesn’t work anymore.. probably since the objects in @posts aren’t pure Post-classes anymore, but some has_finder proxy thingie.
The workaround isn’t that big of a deal though, just go back to using the “old way”:
view:
render :partial “posts/post”, :locals => bla bla …
.. Maybe something could be done so it works with the first way though?
February 7, 2008 at 1:37 am
Oups, sorry for the dups.. didn’t see my comments comming.
And one correction, the way one has to do with has_finder in the view is:
render :partial => “posts/post”, :collection => @posts … which isn’t such a big deal.
February 7, 2008 at 1:46 am