How to get 'photo'_url(...) to work? - ruby-on-rails-3

photo_url(Photo.first, :host => 'foobar') returns http://foobar/photos/2vig0 .
How do I do the same thing with something like 'photo'_url(Photo.first, :host => 'foobar')
Do I need to do something like: 'photo'.constantize._url(Photo.first, :host => 'foobar')

You can use send to invoke a method, once you've concatinated the two parts of the string together.
assuming #fn contains the string "photo":
send("#{#fn}_url", Photo.first, :host => 'foobar')
Or, possibly clearer:
send("photo" + "_url", Photo.first, :host => 'foobar')

How about url_for?
http://api.rubyonrails.org/classes/ActionDispatch/Routing/UrlFor.html#method-i-url_for

Related

scaml interpolation in html attributes

I have something like this:
-# var id:String
%div{:dojoType => 'dojo.data.ItemFileReadStore', :jsType => 'store', :url => "/path/to/resource?id=#{id}"}
I was hoping variable interpolation would work here, but it just puts #{id} into the html. I also tried:
%div{:url => 'path/to/resource?id='+id}
And that doesn't even compile. What is the right way to do this?
The correct syntax is:
%div{:url => {"/path/to/resource?id="+id}}

How do I target an alias from a restriction, with the QueryOver api?

As far as I know, the QueryOver api does not allow you reference an alias by name, but rather you use a typed object. How can I add a restriction to my query that targets the alias?
For example, I would like to accomplish something similar to the following:
var query = session.QueryOver<Person>().JoinQueryOver(x => x.Dogs, () => dogAlias);
return query.Where(Restrictions.Disjunction()
.Add(Restrictions.Like("Name", searchQuery, MatchMode.Anywhere))
.Add(Restrictions.Like("dogAlias.Name", searchQuery, MatchMode.Anywhere)));
instead of:
Restrictions.Like("dogAlias.Name", searchQuery, MatchMode.Anywhere)
use:
Restrictions.On(() => dogAlias.Name).IsLike(searchQuery, MatchMode.Anywhere)
So, the complete query would become:
var query = session.QueryOver<Person>()
.JoinQueryOver(x => x.Dogs, () => dogAlias);
return query.Where(Restrictions.Disjunction()
.Add(Restrictions.On<Person>(p => p.Name).IsLike(searchQuery, MatchMode.Anywhere))
.Add(Restrictions.On(() => dogAlias.Name).IsLike(searchQuery, MatchMode.Anywhere)));

Using dynamic finders to specify NOT NULL

I very often want to use dynamic finders to specify NOT NULL. So…
this works:
Widget.find_all_by_color('blue')
this works:
Widget.find_all_by_color(nil)
But how can I do
SELECT * FROM `widgets` WHERE `color` IS NOT NULL;
?
Two ways depending on how specific you want to be:
# in your model
class Widget < ActiveRecord::Base
# first way
named_scope :coloured, {:conditions => ["color IS NOT NULL"]}
# second way
named_scope :not_null, lambda{|*args| (field=args.first ? {:conditions => ["#{field} is not null",field]} : {}) } }
end
# in your controller
#coloured_widgets = Widget.coloured.all # using first way
#coloured_widgets = Widget.not_null(:colour).all # using second way
I hope it helps.
Cheers
Widget.find(:all, :conditions => "color IS NOT NULL")
Try this:
Widget.all(:conditions => "color IS NOT NULL")
Not quite as elegant, but this should work:
Widget.find(:all, :conditions => "'color' IS NOT NULL")

Optimise ignoring of undefined variables when building find conditions in Rails

I have a an method that retrieves Groups that are present in certain areas. Groups are given a country_id, region_id and city_id
The UI gives three select boxes to choose a country, a region from that country and then a city from that region. To find all groups in a particular city, I have this code:
#groups = Group.find(:all, :conditions => {:city_id => params[:city_id]})
This all works fine, but I also want it to find all groups in an area when the lower criteria isn't specified. For example, If a country and region are given, but not city, I'd like to find it by the region.
What I'm doing is this:
if !params[:city_id].nil?
#groups = Group.find(:all, :conditions => {:city_id => params[:city_id]})
else
if !params[:region_id].nil?
#groups = Group.find(:all, :conditions => {:region_id => params[:region_id]})
else
#groups = Group.find(:all, :conditions => {:country_id => params[:country_id]})
end
end
This works perfectly well, but it seems like it's a little inefficient. Am I doing it the best way or can I streamline a little?
One idea I had was to have a single find checking against all parameters, but I could not work out how to effectively 'ignore' parameters that were nil - my main thought was to check which ones were not set and set them to something like '*' or 'true', but that's not how SQL plays the game.
Sounds like a job for named scopes:
class Group < ActiveRecord::Base
named_scope :in_city, lambda { |city_id| {
:conditions => { :city_id => city_id }
}}
named_scope :in_region, lambda { |region_id | {
:conditions => { :region_id => region_id }
}}
named_scope :in_country, lambda { |country_id | {
:conditions => { :country_id => country_id }
}}
end
This establishes some simple scopes for restricting the Group records. Presumably you have indexed your database properly so these are quick to resolve.
The controller is much easier to implement then:
def index
#group_scope = Group
if (!params[:city_id].blank?)
#group_scope = #group_scope.in_city(params[:city_id])
elsif (!params[:region_id].blank?)
#group_scope = #group_scope.in_region(params[:region_id])
elsif (!params[:country_id].blank?)
#group_scope = #group_scope.in_country(params[:country_id])
end
#groups = #group_scope.all
end
Generally you should be testing for .blank? instead of .nil? as some form elements can send in empty results, such as a select with something akin to "All" as the default.
You could use some Ruby idioms to get something a little more succinct.
Try something like this: (untested code!)
def index
#groups = Group.find :all, :conditions => [:city_id, :region_id, :country_id].inject {} do |conditions, name|
conditions[name] = params[name] unless params[name].blank?
conditions
end
end
If every value in params is a candidate for :conditions you can just do this:
#groups = Group.all(:conditions => params.reject { |idx, val| val.nil? })
This just throws out nil values from params and uses the remaining values for conditions.
If you don't want to use all of the values in params, you have two options. You can just get rid of a bunch of redundancy in your original code:
conditions = if !params[:city_id].nil?
{ :city_id => params[:city_id] }
elsif !params[:region_id].nil?
{ :region_id => params[:region_id] }
else
{ :country_id => params[:country_id] }
end
#groups = Group.all(:conditions => conditions)
You can knock of a few more lines like this, but it sacrifices a bit of readability IMO:
conditions = if !params[:city_id].nil? then { :city_id => params[:city_id] }
elsif !params[:region_id].nil? then { :region_id => params[:region_id] }
else { :country_id => params[:country_id] }
end
Or you can do something like this:
conditions = [:city_id, :region_id, :country_id].inject({}) do |hsh, sym|
hsh[sym] = params[sym] unless params[sym].nil?
hsh
end
#groups = Group.all(:conditions => conditions)
This has the advantage that you don't need to add another condition for each symbol.

Better way of returning the values of a column in Active Record?

Quick one, but thought I'd ask.
Is there a better way of getting the column values from a model's column than something like this?
Item.count(:all, :group => 'status').reject! { |i, e| i.blank? }.collect { |i,e| i}
Item.find(:all, :select=>:status, :group => 'status', :conditions => "status != ''").collect{|r| r.status}
Is it the same thing as the following code?
Item.count(:all, :group => "status", :conditions => "status != ''"}
.. maybe not ..
but then could you please specify more criteria you want? i.e. status is blank? count is blank?