ThinkingSphinx excerpt issue with associations with special chars - ruby-on-rails

I'm having an issue with special characters (apostrophe, namely), only when present is a nested association, however.
I have a 'Vendor' model and an 'Event' model, where a Vendor has_many Events. Here are the index files:
vendor_index:
ThinkingSphinx::Index.define :vendor, :with => :active_record do
indexes :name
indexes city
set_property :min_prefix_len => 2
set_property :enable_star => true
end
event_index:
ThinkingSphinx::Index.define :event, :with => :active_record do
indexes title
indexes subtitle
indexes venue_name
indexes vendor.name, :as => :vendor_name
indexes vendor.city, :as => :vendor_city
indexes genre.name, :as => :genre_name
where "workflow_state = 'published'"
set_property :min_prefix_len => 2
set_property :enable_star => true
end
I'm using an ExcerptorPane, like so, in my search#index action :
class SearchController < ApplicationController
helper_method :format_autocomplete
def index
#events = Event.search params[:search], {:star => true , :per_page => 5, :page => params[:events_page]}
#events.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
#vendors = Vendor.search params[:search], { :star => true , :per_page => 5, :page => params[:vendors_page]}
#vendors.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
#users = User.search params[:search], { :star => true , :per_page => 5, :page => params[:users_page]}
#users.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
end
# methods used for ajax-y pagination
def vendor_results
#vendors = Vendor.search params[:search], { :star => true , :per_page => 5, :page => params[:vendors_page]}
#vendors.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
respond_to do |format|
format.js
end
end
def user_results
#users = User.search params[:search], { :star => true , :per_page => 5, :page => params[:users_page]}
#users.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
respond_to do |format|
format.js
end
end
def event_results
#events = Event.search params[:search], { :star => true , :per_page => 5, :page => params[:events_page]}
#events.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
respond_to do |format|
format.js
end
end
def get_terms
results = ThinkingSphinx.search(params[:search], {:star => true})
results.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
results_json = format_autocomplete(results)
respond_to do |format|
format.js { render :json => results_json }
end
end
private
def format_autocomplete(r)
bucket = [];
r.each do |result|
puts result.class
if result.class.name == "Event"
title = result.excerpts.title
name = result.excerpts.vendor_name
bucket << {
:label => title,
:value => title,
:category => "Events",
:subtitle => result.excerpts.subtitle,
:url => event_url(result),
:vendor_name => name,
:vendor_city => result.excerpts.vendor_city,
:genre_name => result.excerpts.genre_name,
:venue_name => result.excerpts.venue_name
}
elsif result.class.name == "Vendor"
name = result.excerpts.name
bucket << {
:label => name,
:value => name,
:category => "Vendors",
:subtitle => result.excerpts.city,
:url => vendor_url(result)
}
elsif result.class.name == "User"
name = result.excerpts.name
bucket << {
:label => name,
:value => name,
:category => "Users",
:subtitle => result.excerpts.city,
:url => user_url(result)
}
end
end
bucket
end
end
I have also included a charset_table and ignore_chars in my thinking_sphinx.yml file.
Now, when I search for a Vendor with an apostrophe in their name, everything goes fine if the Vendor has no events. If a Vendor has events though, I get an error trying to render the event's vendor_name: (the full vendor name is "VIFF's Vancity Theatre, and the search query is 'viff')
sphinxql: syntax error, unexpected IDENT, expecting ')' near 's Vancity Theatre', 'event_core', '*viff*', '<span class="match">' AS before_match, '</span>' AS after_match, ' … ' AS chunk_separator)'
raised at this line in my view:
<p><%= link_to ( raw event.excerpts.vendor_name ), vendor_path(event.vendor) %></p>
I've been searching for a while, but can't find anything of help...Any ideas as to what might be causing this?
Thanks!
UPDATE:
It gets weirder ... with vendor name "Viff's Vancity Theatre", (and all events and vendors have city = 'Vancouver' ) if I search "van" or "vanc", everything renders fine, with "Vancity" marked as a match. However if I search "vanco" it breaks again. This happens when I am performing a search on specific models. When I perform a global search however (for autocomplete), I get the opposite behaviour - 'vanco' will work, but anything shorter throws back the same error. I've updated the code above with the full search_controller.rb.

I just received a pull request for Riddle that may contain a fix for this. Try adding the following to your Gemfile:
gem 'riddle', '~> 1.5.6',
:git => 'git://github.com/pat/riddle.git',
:branch => 'master',
:ref => '50d410cda6'

Related

How to access a hash by key

I'm trying to build a Rails helper that will create a nested dropdown menu containing links where the top most is either "All" or the current param and the dropdown contains the other options excluding the current param if there is one.
For example, if I have no post_type param I would see:
<ul>
<li>All
<ul>
<li>Discussions</li>
<li>Snaps</li>
<li>Code</li>
<li>Links</li>
</ul>
</li>
</ul>
But if I had a post_type param of 'discussion' then I would see:
<ul>
<li>Discussions
<ul>
<li>All</li>
<li>Snaps</li>
<li>Code</li>
<li>Links</li>
</ul>
</li>
</ul>
In my view I have:
<ul class="filter-menu">
<li>
<%= current_post_type(params) %>
<ul class="filter-menu__drop-down">
<%= list_post_types(params) %>
</ul>
</li>
</ul>
In my Helper I have:
module PostsHelper
def post_types
#post_types = {
:all => {
:text => 'All post types',
:icon => 'icon-file-text2',
:post_type => nil}
}, {
:discussions => {
:text => 'Discussions',
:icon => 'icon-bubbles2',
:post_type => 'discussions'}
}, {
:snaps => {
:text => 'Snaps',
:icon => 'icon-images',
:post_type => 'snaps'}
}, {
:code => {
:text => 'Code',
:icon => 'icon-embed2',
:post_type => 'code'}
}, {
:links => {
:text => 'Links',
:icon => 'icon-link',
:post_type => 'links'}
}
end
def post_type_text(icon, text, drop_down = false)
raw('<i class="' + icon + '"></i> ' + text + (drop_down ? ' <span class="chevron">▾</span>' : ''))
end
def post_type_path(post_type)
posts_path(:filter => params[:filter], :time => params[:time], :post_type => post_type)
end
def current_post_type(params)
if params[:post_type].present? # todo: check matches above
post_type = params[:post_type].downcase
link_to post_type_text(post_types[post_type][:icon], post_types[post_type][:text], true), post_type_path(post_types[post_type][:post_type])
else
link_to post_type_text(post_types[:all][:icon], post_types[:all][:text], true), post_type_path(post_types[:all][:post_type])
end
end
def list_post_types(params)
post_types.each do |post_type| # todo: exclude current post_type
link_to post_type_text(post_types[post_type][:icon], post_types[post_type][:text]), post_type_path(post_types[post_type][:post_type])
end
end
end
How do I access the hash though? I get an error
no implicit conversion of Symbol into Integer
when doing post_types[:all].
I think it's because post_types is returning an array of hashes where as what I want is a hash of hashes accessible by key names.
I could access the :all via post_types[0][:all][:icon] but this won't work for my other hashes, as I want to access them via post_types[post_type][:icon] where post_type is the name of the post_type key I am trying to access.
First of all, declare a hash instead of an array:
#post_types ||= {
:all => {
:text => 'All post types',
:icon => 'icon-file-text2',
:post_type => nil},
:discussions => {
:text => 'Discussions',
:icon => 'icon-bubbles2',
:post_type => 'discussions'},
:snaps => {
:text => 'Snaps',
:icon => 'icon-images',
:post_type => 'snaps'},
:code => {
:text => 'Code',
:icon => 'icon-embed2',
:post_type => 'code'},
:links => {
:text => 'Links',
:icon => 'icon-link',
:post_type => 'links'}
}
The problem is here:
post_types.each do |post_type| # todo: exclude current post_type
link_to post_type_text(post_types[post_type] ...
You are already iterating over your hash, post_type here is an array, holding both key and value.
Use:
post_types.each do |k, v| # todo: exclude current post_type
link_to post_type_text(v[:icon] ...
To understand what’s going on:
post_types.each do |post_type| # todo: exclude current post_type
puts post_type.inspect
Also, sidenote: instantiate the instance variable only once:
def post_types
# ⇓⇓⇓ HERE
#post_types ||= {...}
This what I have ended up with in the end to solve my problem.
Massive thanks to mudasobwa whose answer I have accepted but I wanted to share what the final code looked like for anyone who comes across this.
module PostsHelper
def post_types
#post_types ||= {
:all => {
:text => 'All post types',
:icon => 'icon-file-text2',
:post_type => nil},
:discussions => {
:text => 'Discussions',
:icon => 'icon-bubbles2',
:post_type => 'discussions'},
:snaps => {
:text => 'Snaps',
:icon => 'icon-images',
:post_type => 'snaps'},
:code => {
:text => 'Code',
:icon => 'icon-embed2',
:post_type => 'code'},
:links => {
:text => 'Links',
:icon => 'icon-link',
:post_type => 'links'}
}
end
def post_type_text(icon, text, drop_down = false)
raw('<i class="' + icon + '"></i> ' + text + (drop_down ? ' <span class="chevron">▾</span>' : ''))
end
def post_type_path(post_type)
posts_path(:filter => params[:filter], :time => params[:time], :post_type => post_type)
end
def current_post_type(params)
post_type = params[:post_type].present? ? params[:post_type].downcase.to_sym : :all
if post_types.key?(post_type)
link_to post_type_text(post_types[post_type][:icon], post_types[post_type][:text], true), post_type_path(post_types[post_type][:post_type])
else
link_to post_type_text(post_types[:all][:icon], post_types[:all][:text], true), post_type_path(post_types[:all][:post_type])
end
end
def list_post_types(params)
html = ''
post_type = params[:post_type].present? ? params[:post_type].downcase.to_sym : :all
exclude_all = post_types.key?(post_type) ? false : true
post_types.each do |k, v|
if exclude_all && k == :all
else
html += "<li>#{link_to post_type_text(v[:icon], v[:text]), post_type_path(v[:post_type])}</li>" if k != post_type
end
end
html.html_safe
end
end

showing error "uninitialized constant Spree::ProductTaxon" while updating spree_products_taxons table in spree

I want to update spree_products_taxons table, but it is showing the error above. What am I am doing wrong?
def import_update
require 'csv'
file = params[:file]
CSV.foreach(file.path, headers: true) do |row|
#prod = Spree::Product.find(row["id"])
#var = Spree::Variant.find_by(product_id: #prod.id)
Spree::Product.where(:id => row["id"]).update_all(:name => row["name"], :meta_description => row["meta_description"], :shipping_category_id => row["shipping_category_id"], :description => row["description"], :meta_keywords => row["meta_keywords"], :tax_category_id => row["tax_category_id"], :available_on => row["available_on"], :deleted_at => row["deleted_at"], :promotionable => row["promotionable"], :meta_title => row["meta_title"], :featured => row["featured"], :supplier_id => row["supplier_id"])
Spree::Variant.find_by(id: #var.id).update(:cost_price => row["cost_price"], :depth => row["depth"], :height => row["height"], :width => row["width"], :weight => row["weight"], :tax_category_id => row["tax_category_id"], :is_master => row["is_master"], :position => row["position"], :cost_currency => row["cost_currency"], :deleted_at => row["deleted_at"], :track_inventory => row["track_inventory"], :tax_category_id => row["tax_category_id"])
Spree::Price.find_by(variant_id: #var.id).update(:amount => row["master_price"], :currency => row["cost_currency"], :deleted_at => row["deleted_at"])
Spree::ProductTaxon.find_by(product_id: #prod.id).update(:taxon_id => row["taxon_id"])
#prop = Spree::ProductProperty.find_by(product_id: #prod.id)
Spree::Property.find_by(id: #prop.property_id).update(:name => row["name"], :presentation => row["presentation"])
Spree::ProductProperty.find_by(product_id: #prod.id).update(value => row["value"])
stock_loc = Spree::StockLocation.find_by(supplier_id: #prod.supplier_id)
Spree::StockItem.where(:variant_id => #variants.id, :stock_location_id => stock_loc.id).update_all(:count_on_hand => row["count_on_hand"], :backorderable => row["backorderable"])
end
redirect_to admin_products_path, notice: "Products Updated."
end
Although the table is called spree_products_taxons (see schema.rb) for some reason the model is Spree::Classification.
You table is spree_products_taxons so it's expecting Spree::ProductsTaxon (mind that its Products NOT Product) model class. Make sure your model should be named as Spree::ProductsTaxon
I can see you are using Spree::ProductTaxon in your code. Please update and try.
Hope it helps.

how to do ccavenuee payment gateway integration in rails

I tried ccavenue but I'am getting this error. paypal is working fine.
undefined methodpayment_service_for'`
This is my controller action
def create
#subscription = Subscription.new(subscription_params)
#programme = Programme.find(subscription_params[:programme_id])
rand_number = rand.to_s[2..11]
#programme.update_attributes(:invoice_id => rand_number)
session[:programme_id]=#programme.id
session[:invoice_id]=#programme.invoice_id
#paypal = PaypalPayment.create(:material_type => 'Programmes',:invoice_id => rand_number,:currency => #programme.currency, :status => 'Processing', :created_at => DateTime.now, :user_id => current_user.specific.id, :email_id => current_user.specific.email, :programme_id => #programme.id,:amount => #programme.price_paisas)
#paypal.save
`session[:paypal_id]=#paypal.id
logger.info #programme.inspect
if subscription_params[:payment_type] == 'paypal'
item_details=[]
if #programme.currency == 'INR'
price = #programme.price.exchange_to('USD')
else
price = #programme.price
end
logger.info price.inspect
item_details << {:name => #programme.title, :quantity => '1', :amount => price.fractional}
response = EXPRESS_GATEWAY.setup_purchase(price.fractional,
:items => item_details,
:currency => "USD",
:order_id => #programme.invoice_id,
:return_url => students_success_url,
:cancel_return_url => students_root_url
)
logger.info response.inspect
session[:programme_price]=price
return redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token)
elsif subscription_params[:payment_type] == 'ccavenue'
payment_service_for #programme.invoice_id, CCAVENUE_ACCOUNT,
:amount => #programme.price.fractional,
:currency => 'INR',
:service => :ccavenue do |service|
service.customer :name => current_user.name,
:email => current_user.email,
:phone => current_user.mobile
service.redirect :return_url => students_success_url
submit_tag 'Proceed to payment'
end
end
end
end`
I referred this link:
https://github.com/meshbrain/active_merchant_ccavenue
The payment_service_for is the view helper of the Active Merchant gem. You should use this method inside views or you should include view helpers inside your controller.

AJAX update of accepts_nested_attributes_for partials

My current working environment is Rails 2.3.8 (various reasons why my company hasn't moved to Rails 3).
I'm trying to update elements of a multi-model form via AJAX calls - the idea being to replace certain dropdowns depending on how the user selects or fills in other fields.
I have previously managed to get this working by using non-form based partials - the problem I have now is to reproduce the AJAX updating of the select dropdowns when the partials are based around form_for and fields_for.
Sorry for the following wall of text - i've tried to cut it down as much as possible (the code itself does work on my test site).
How do I generate the form builder elements in the Outbreak controller and then pass this to the category partial to take the place of incident_form?
Any pointers would be great :D
Models
class Outbreak < ActiveRecord::Base
has_many :incidents, :dependent => :destroy
has_many :locations, :through => :incidents
accepts_nested_attributes_for :locations, :allow_destroy => true, :reject_if => :all_blank
accepts_nested_attributes_for :incidents, :allow_destroy => true, :reject_if => :all_blank
end
class Incident < ActiveRecord::Base
belongs_to :outbreak
belongs_to :location
belongs_to :category
belongs_to :subcategory
belongs_to :subtype
end
class Location < ActiveRecord::Base
has_many :incidents, :dependent => :destroy
has_many :outbreaks, :thorugh => incidents
end
Views
_form
<% form_for(#outbreak, :html => {:multipart => true}) do |form| %>
<%= render :partial => 'outbreak_type_select', :locals => {:outbreak_types => #outbreak_types, :f => form } %>
<% form.fields_for :incidents do |incident_form| %>
<%= render :partial => 'category_select', :locals => {:categories => #categories, :incident_form => incident_form} %>
<%= render :partial => 'subcategory_select', :locals => { :subcategories => #subcategories, :incident_form => incident_form } %>
<% end %>
<% end %>
_outbreak_type_select
<% with_str = "'outbreak_type=' + value " %>
<% if #outbreak.id %>
<% with_str << "+ '&id=' + #{outbreak.id}" %>
<% end %>
<%= f.collection_select(:outbreak_type, #outbreak_types, :property_value, :property_value, {}, {:onchange => "#{remote_function(:url => { :action => "update_select_menus"}, :with => with_str)}"} ) %>
_category_select
After calling update_select_menus how to generate the incident_form
<%= incident_form.collection_select( :category_id, #categories, :id, :name, {:prompt => "Select a category"}, {:onchange => "#{remote_function(:url => { :action => "update_subcategory"}, :with => "'category_id='+value")}"}) %>
RJS
begin
page.replace_html 'outbreak_transmission_div', :partial => 'outbreaks/transmission_mode_select', :locals => {:transmission_modes => #transmission_modes }
rescue
page.insert_html :bottom, 'ajax_error', '<p>Error :: transmission modes update select</p>'
page.show 'ajax_error'
end
begin
page.replace_html 'incident_category_select', :partial => 'outbreaks/category_select', :locals => { :categories => #categories }
rescue
page.insert_html :bottom, 'ajax_error', '<p>Error :: incident category update select</p>'
page.show 'ajax_error'
end
Controllers
Outbreak
def new
#outbreak = Outbreak.new
#outbreak.incidents.build
#outbreak.locations.build
#just the contents for the dropdowns
#categories = Category.find(:all, :conditions => {:outbreak_type => "FOODBORNE"}, :order => "outbreak_type ASC")
#subcategories = Subcategory.find(:all, :order => "category_id ASC")
end
def update_select_menus
#outbreak_type = params[:outbreak_type].strip
if params[:id]
#outbreak = Outbreak.find(params[:id])
else
#outbreak = Outbreak.new
#outbreak.incidents.build
#outbreak.locations.build
end
if #outbreak_type == "FOODBORNE"
ob_type_query = "OUTBREAKS:TRANSMISSION_MODE:" << #outbreak_type
#transmission_modes = Property.find(:all, :conditions => {:field => ob_type_query})
ob_type_query = "INVESTIGATIONS:CATEGORY:" << #outbreak_type
#sample_types = Property.find(:all, :conditions => {:field => ob_type_query})
#categories = Category.find(:all, :conditions => { :outbreak_type => "FOODBORNE"})
#subcategories = Subcategory.find(:all, :conditions => { :category_id => #categories.first.id})
#subtypes = Subtype.find(:all, :conditions => { :subcategory_id => #subcategories.first.id})
elsif #outbreak_type == "NON-FOODBORNE"
ob_type_query = "OUTBREAKS:TRANSMISSION_MODE:" << #outbreak_type
#transmission_modes = Property.find(:all, :conditions => {:field => ob_type_query})
ob_type_query = "INVESTIGATIONS:CATEGORY:" << #outbreak_type
#sample_types = Property.find(:all, :conditions => {:field => ob_type_query})
#categories = Category.find(:all, :conditions => { :outbreak_type => "NON-FOODBORNE"})
#subcategories = Subcategory.find(:all, :conditions => { :category_id => #categories.first.id})
#subtypes = Subtype.find(:all, :conditions => { :subcategory_id => #subcategories.first.id})
end
respond_to do |format|
format.html
format.js
end
end
Found a work around based on http://www.treibstofff.de/2009/07/12/ruby-on-rails-23-nested-attributes-with-ajax-support/
This should probably go in Outbreak helper (in Outbreak controller atm)
def update_select_menus
#outbreak_type = params[:outbreak_type].strip
#next_child_index will only be used if
#next_child_index ? params[:next_child_index] : 0
if params[:id]
#outbreak = Outbreak.find(params[:id])
else
#outbreak = Outbreak.new
#outbreak.risks.build
#outbreak.incidents.build
#outbreak.locations.build
end
if #outbreak_type == "FOODBORNE"
ob_type_query = "OUTBREAKS:TRANSMISSION_MODE:" << #outbreak_type
#transmission_modes = Property.find(:all, :conditions => {:field => ob_type_query})
ob_type_query = "INVESTIGATIONS:CATEGORY:" << #outbreak_type
#sample_types = Property.find(:all, :conditions => {:field => ob_type_query})
#categories = Category.find(:all, :conditions => { :outbreak_type => "FOODBORNE"})
#subcategories = Subcategory.find(:all, :conditions => { :category_id => #categories.first.id})
#subtypes = Subtype.find(:all, :conditions => { :subcategory_id => #subcategories.first.id})
elsif #outbreak_type == "NON-FOODBORNE"
ob_type_query = "OUTBREAKS:TRANSMISSION_MODE:" << #outbreak_type
#transmission_modes = Property.find(:all, :conditions => {:field => ob_type_query})
ob_type_query = "INVESTIGATIONS:CATEGORY:" << #outbreak_type
#sample_types = Property.find(:all, :conditions => {:field => ob_type_query})
#categories = Category.find(:all, :conditions => { :outbreak_type => "NON-FOODBORNE"})
#subcategories = Subcategory.find(:all, :conditions => { :category_id => #categories.first.id})
#subtypes = Subtype.find(:all, :conditions => { :subcategory_id => #subcategories.first.id})
end
#pathogen_types = Property.find(:all, :conditions => {:field => "PATHOGENS:CATEGORY"})
#outbreak_types = Property.find(:all, :conditions => {:field => "OUTBREAKS:OUTBREAK_TYPE"} )
render :update do |page|
page.replace 'outbreak_transmission_div', :partial => 'transmission_mode_select_update'
page.replace 'incident_category_select', :partial => 'incident_category_select_update'
page.replace 'incident_subcategory_select', :partial => 'incident_subcategory_select_update'
page.replace 'incident_subtype_select', :partial => 'incident_subtype_select_update'
end
end
In the Outbreak view (although since this partial is related to Incident it should probably go in that view instead)
<% ActionView::Helpers::FormBuilder.new(:outbreak, #outbreak, #template, {}, proc{}).fields_for :incidents,{:child_index => #next_child_index} do |this_form| %>
<div id="incident_category_select">
<%= render :partial => 'category_select', :locals => {:incident_form => this_form } %>
</div>
<% end %>
The ActionView::Helpers::FormBuilder is used to produce the required fields_for form - The website article goes through this in more detail.
The resulting index is set by the #next_child_index variable which can be passed to the controller by the original AJAX call (for example #next_child_index = 1, then the resulting form element name will be outbreak [incidents_attributes] [1] [category_id] ) - I haven't used this in this example because although in future I want the form to support more than one location per Outbreak for this initial run-through it will just accept a single Location - Incident per Outbreak.
_category_select.erb partial (in Outbreak view atm)
<% with_str = "'category_id=' + value " %>
<% if #outbreak.id %>
<% with_str << "+ '&id=' + #{#outbreak.id}" %>
<% end %>
<%= incident_form.collection_select( :category_id, #categories, :id, :name, {:prompt => "Select a category"}, {:onchange => "#{remote_function(:url => { :action => "update_subcategory"}, :with => with_str)}"}) %>
The with_str is just to optionally pass the Outbreak id if it exists to the controller to find the Outbreak record to produce the form and if not to build a new Outbreak and associated nested attributes like Incidents and Locations.
The must be neater ways of doing this - especially the FormHelper and passing the Outbreak id via the optional with string.

Rails ActiveRecord conditions

Is there a way to create a condition like this?
#products = Product.find(:all,
:limit => 5,
:conditions => { :products => { :locale => 'en', :id NOT '1' }, :tags => { :name => ['a','b']})
I would like to list all products not including product 1.
Thx.
Rails 3
Use squeel gem.
Product.where(
:products => { :locale => 'en', :id.not_in => '1' },
:tags => { :name => ['a','b']}
).limit(5)
Rails 2
Use AR Extensions for this. It supports the following condition modifiers:
* _lt => less than
* _gt => greater than
* _lte => less than or equal to
* _gte => greater than or equal to
* _ne => not equal to
* _not => not equal to
Now you can rewrite your query as follows:
#products = Product.find(:all,
:limit => 5,
:joins => [:tags],
:conditions => { :locale => 'en', :id_not => '1', :tags => { :name => ['a','b']}
)
It should be something like this. The original query wasn't really clear, adapt it to your needs.
#products = Product.find(:all,
:limit => 5,
:conditions => ["locale = ? AND id <> ? AND tags.name IN (?)", "en", 1, ['a','b'],
:joins => "tags"
)
Another way is to use the merge_conditions which turns the hash conditions into a string. Then you can add on whatever you want or call merge_conditions again with other options.
hash_conditions = {:category => 'computers'}
conditions = Product.merge_conditions(hash_conditions) + ' AND products.id NOT IN(1139) '
products = Product.find(:all, :conditions => conditions)
Rails 3.2.9
Controller
#products = Product.english_but_not(1).with_tags('a','b').limit(5)
Model
class Product < ActiveRecord::Base
attr_accessible :locale
has_many :tags
scope :english, -> { where(:locale => 'en') }
scope :except_id, ->(id) { where(arel_table[:id].not_eq(id)) }
scope :english_but_not, ->(id) { english.except_id(id) }
scope :with_tags, ->(*names) { includes(:tags).where(:tags => {:name => names}) }
end

Resources