I have a search form which works very well but I want to add keyword functionality to it. I'm not sure how. The search conditions look like this:
def search
conditions = {}
conditions[:targ_lang] = params[:targ_lang] unless params[:targ_lang].blank?
conditions[:inst_lang] = params[:inst_lang] unless params[:inst_lang].blank?
conditions[:start_level] = params[:start_level] unless params[:start_level].blank?
conditions[:end_level] = params[:end_level] unless params[:end_level].blank?
conditions[:skill] = params[:skill] unless params[:skill].blank?
conditions[:subject] = params[:subject] unless params[:subject].blank?
conditions[:inst_name] = params[:inst_name] unless params[:inst_name].blank?
conditions[:creator] = params[:creator] unless params[:creator].blank?
#conditions = Material.where("keywords like ?", "%#{keywords}") unless params[:keywords].blank?
#results = Material.find(:all, :conditions => conditions)
end
I've commented out the keyword line because it doesn't work at the moment. Obviously it's different to the others because we don't want to find an exact match, we want a single match from several possible keywords.
Can anyone help? Rookie question I know but I've been working on it for a while.
Related
I have a materials model which has a search form. The search action looks a bit like this:
def search
conditions = {}
conditions[:version] = 'master'
conditions[:status] = 'shared'
conditions[:targ_lang] = params[:targ_lang] unless params[:targ_lang].blank?
#results = Material.find(:all, :conditions => conditions)
end
I have added the acts-as-taggable gem and it works fine to save the tags but I'm having trouble adding it to the search form. The documentation states that to find Materials with the tags you can use this code:
Material.tagged_with(["awesome", "cool"], :match_all => true)
But I don't know how to add this condition to the conditions.
Update
#results = Material.where(conditions) && Material.tagged_with(params[:tag_list])
This works provided tags are used but it doesn't work if the tag list is blank so I need a condition as with the other conditions above that the Material.tagged_with ... part is only necessary if the field is not empty.
Update 2 - Bad Solution
This works but it's not very elegant is it?
if params[:tag_list].blank?
#results = Material.where(conditions)
else
#results = Material.tagged_with(params[:tag_list]).where(conditions)
end
This code won't work for you?
Material.where(conditions).tagged_with(['awesome', 'cool'], :match_all => true)
Or the inverse order:
Material.tagged_with(['awesome', 'cool'], :match_all => true).where(conditions)
UPDATE
Reading the docs on the act-as-taggable-one on github, there is a option named :any. Maybe you can try to use it. I don't have a project i could do some testing, but maybe a code like:
Material.tagged_with(['awesome', 'cool', '', nil], :any => true).where(conditions)
Give it a try.
i've got a many_many relation in my Task Model
'keywordlist' => array(self::MANY_MANY, 'Keyword', 'task_keyword(id_task, id_keyword)'),
Well i get my List of all those Tasks with
$criteria = new CDbCriteria();
$criteria->condition = "t.blocked = 0 AND t.answered = 0 AND t.date_deadline > NOW()";
$criteria->order = 't.id desc';
Ok, now a task could have one or * keywords. if i put a filter on my Tasks with
$criteria->addCondition('keywordlist.name like \'%html%\'','AND');
i receive the wanted task, but only with the html keyword. the task also have more other keywords which wont appear.
how can i create something like in_array from the keywordlist.name column. and if the keyword is in the result return all the keywords to my task?
if i use for example %p% as the keyword search, it shows up more keywords, if a keyword consists of something with 'p'. but also the other keywords wont show up.
If I understood correctly addInCondition() is what you are looking for
$criteria->addInCondition('keywordlist.name',array('html','add','other','keywords','here'));
I'm trying to work out a more efficient way to add a note count, with a couple of simple where conditions applied to the query. This can take forever, though, as there are as many as 20K records to iterate over. Would welcome any thinking on this.
def reblog_array(notes)
data = []
notes.select('note_type, count(*) as count').where(:note_type => 'reblog', :created_at => Date.today.years_ago(1)..Date.today).group('DATE(created_at)').each do |n|
data << n.count
end
return data
end
This is what's passed to reblog_array(notes) from my controller.
#tumblr = Tumblr.find(params[:id])
#notes = Note.where("tumblr_id = '#{#tumblr.id}'")
From what I can tell, you are trying to calculate how many reblogs/day this Tumblr account/blog had? If so,
notes.where(:note_type => 'reblog', :created_at => Date.today.years_ago(1)..Date.today).group('DATE(created_at)').count.values
should give you the right result, without having to iterate over the result list again. One thing to note, your call right now won't indicate when there are days with 0 reblogs. If you drop the call to #values, you'll get a hash of date => count.
As an aside and in case you didn't know, I'd also suggest making more use of the ActiveRecord relations:
Class Tumblr
has_many :notes
end
#tumblr = Tumblr.find(params[:id])
#notes = #tumblr.notes
this way you avoid writing code like Note.where("tumblr_id = '#{#tumblr.id}'"). It's best to avoid string-interpolated parameters, in favour of code like Note.where(:tumblr_id => #tumblr.id) or Note.where("tumblr_id = ?", #tumblr.id) to leave less chance that you'll write code vulnerable to SQL injection
I want to be able to specify user specific conditions in a MAX() sql call in the :select portion of the active record query (Rails 2.3.12). Unfortunately the safe string interpolation doesn't seem to work for the :select condition. The code is below, is there any other way to manually ensure the incoming values are safe? (They should be as they're just id's but you can never be too sure.)
:select => ["`component_instances`.*, max(`users`.id = ? AND `permissions`.view = 1) AS user_view, max(`users`.id = ? AND `permissions`.edit = 1) AS user_edit", user.id]
The query is designed to indicate to me if a particular user has explicit permissions on a particular item in the site. It'll either return 1 (they do), 0 (they don't but others do), or nil (no one has explicit permissions).
Turns out you can manually use the sanitize_sql_array method to do this:
:select => sanitize_sql_array(["`component_instances`.*, max(`users`.id = ? AND `permissions`.view = 1) AS user_view, max(`users`.id = ? AND `permissions`.edit = 1) AS user_edit", user.id, user.id])
I was wondering if there was a way to use "find_by_sql" within a named_scope. I'd like to treat custom sql as named_scope so I can chain it to my existing named_scopes. It would also be good for optimizing a sql snippet I use frequently.
While you can put any SQL you like in the conditions of a named scope, if you then call find_by_sql then the 'scopes' get thrown away.
Given:
class Item
# Anything you can put in an sql WHERE you can put here
named_scope :mine, :conditions=>'user_id = 12345 and IS_A_NINJA() = 1'
end
This works (it just sticks the SQL string in there - if you have more than one they get joined with AND)
Item.mine.find :all
=> SELECT * FROM items WHERE ('user_id' = 887 and IS_A_NINJA() = 1)
However, this doesn't
Items.mine.find_by_sql 'select * from items limit 1'
=> select * from items limit 1
So the answer is "No". If you think about what has to happen behind the scenes then this makes a lot of sense. In order to build the SQL rails has to know how it fits together.
When you create normal queries, the select, joins, conditions, etc are all broken up into distinct pieces. Rails knows that it can add things to the conditions without affecting everything else (which is how with_scope and named_scope work).
With find_by_sql however, you just give rails a big string. It doesn't know what goes where, so it's not safe for it to go in and add the things it would need to add for the scopes to work.
This doesn't address exactly what you asked about, but you might investigate 'contruct_finder_sql'. It lets you can get the SQL of a named scope.
named_scope :mine, :conditions=>'user_id = 12345 and IS_A_NINJA() = 1'
named_scope :additional {
:condtions => mine.send(:construct_finder_sql,{}) + " additional = 'foo'"
}
sure why not
:named_scope :conditions => [ your sql ]