regex match mongoid condition - ruby-on-rails-3

I have item[:name] and I would like to be able to use
(item[:name].scan(/[a-z0-9\s]/i).join rescue "") =~ Regexp.new(business.scan(/[a-z0-9\s]/i).join, true)
as a condition in mongoid. Is there a way to do this? The only solution I have come up with is getting all items, then iterating over that array, doing the regex at that point in time.
The goal of this is to find "John's" when the website is searched for "Johns" and vice versa.
Thanks

Here is what i ended up using.
def self.find_by_name_or_organization(business = nil)
businesses = self.all(:order => "name ASC")
businesses.delete(nil)
if business && !(business.nil? || business.to_s == '')
final_business_array = Array.new
businesses.each do |item|
if (item[:organization].scan(/[a-z0-9\s]/i).join rescue "") =~ Regexp.new(business.scan(/[a-z0-9\s]/i).join, true) ||
(item[:name].scan(/[a-z0-9\s]/i).join rescue "") =~ Regexp.new(business.scan(/[a-z0-9\s]/i).join, true)
final_business_array.push(item)
end
end
final_business_array
else
businesses
end
end

Related

Rails ActiveRecord where clause

I want to select Cars from database with where clause looking for best DRY approach for my issue.
for example I have this two parameters
params[:car_model_id] (int)
params[:transmission_id] (int)
params[:from_date]
params[:to_date]
but I dont know which one will be null
if params[:car_model_id].nil? && !params[:transmission_id].nil?
if params[:from_date].nil? && params[:from_date].nil?
return Car.where(:transmission_id => params[:transmission_id])
else
return Car.where(:transmission_id => params[:transmission_id], :date => params[:from_date]..params[:to_date])
end
elseif !params[:car_model_id].nil? && params[:transmission_id].nil?
if params[:from_date].nil? && params[:from_date].nil?
return Car.where(:car_model_id=> params[:car_model_id])
else
return Car.where(:car_model_id=> params[:car_model_id], :date => params[:from_date]..params[:to_date])
end
else
return Car.where(:car_model_id=> params[:car_model_id], :transmission_id => params[:transmission_id], :date => params[:from_date]..params[:to_date])
end
what is best approach to avoid such bad code and check if parameter is nil inline(in where)
You can do:
car_params = params.slice(:car_model_id, :transmission_id).reject{|k, v| v.nil? }
and then:
Car.where(car_params)
Explanation: Since, you're checking if the particular key i.e.: :car_model_id and transmission_id exists in params. The above code would be something like this when you have just :transimission_id in params:
Car.where(:transmission_id => '1')
or this when you have :car_model_id in params:
Car.where(:car_model_id => '3')
or this when you'll have both:
Car.where(:transmission_id => '1', :car_model_id => '3')
NOTE: This will work only when you have params keys as the column names for which you're trying to run queries for. If you intend to have a different key in params which doesn't match with the column name then I'd suggest you change it's key to the column name in controller itself before slice.
UPDATE: Since, OP has edited his question and introduced more if.. else conditions now. One way to go about solving that and to always keep one thing in mind is to have your user_params correct values for which you want to run your queries on the model class, here it's Car. So, in this case:
car_params = params.slice(:car_model_id, :transmission_id).reject{|k, v| v.nil? }
if params[:from_date].present? && params[:from_date].present?
car_params.merge!(date: params[:from_date]..params[:to_date])
end
and then:
Car.where(car_params)
what is best approach to avoid such bad code and check if parameter is
nil inline(in where)
Good Question !
I will make implementation with two extra boolean variables (transmission_id_is_valid and
car_model_id_is_valid)
transmission_id_is_valid = params[:car_model_id].nil? && !params[:transmission_id].nil?
car_model_id_is_valid = !params[:car_model_id].nil? && params[:transmission_id].nil?
if transmission_id_is_valid
return Car.where(:transmission_id => params[:transmission_id])
elseif car_model_id_is_valid
return Car.where(:car_model_id=> params[:car_model_id])
....
end
I think now is more human readable.
First, I would change this code to Car model, and I think there is no need to check if params doesn't exists.
# using Rails 4 methods
class Car < ActiveRecord::Base
def self.find_by_transmission_id_or_model_id(trasmission_id, model_id)
if transmission_id
find_by trasmission_id: trasmission_id
elsif model_id
find_by model_id: model_id
end
end
end
In controller:
def action
car = Car.find_by_transmission_id_or_model_id params[:trasmission_id], params[:car_model_id]
end
edit:
This code is fine while you have only two parameters. For many conditional parameters, look at ransack gem.

Why am I not able to call a static function in my Rspec class

I am new to rails and have just started writing tests using rspec version : 2.11.1 . I am looking for a way to seed different data for different tests in my class. For this I created a static function in the test itself. Depending on the requirements I am in instantiating different number of objects. I have a function seed_data which instantiates different number of objects based on the number passed to it. I get this exception :
NoMethodError: undefined method `seed_data' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_5::Nested_1:0x007fcedd9bea70>
Please have a look at the sample code below :
require 'spec_helper'
require 'go_live_sale'
require 'rspec/expectations'
describe GoLiveSale do
context "get_go_live_sale_for_sale_ids Function Correctness" do
describe "Testing get_go_live_sale_for_sale_ids() function correctness " do
it "should return error when sale_ids is blank" do
result = GoLiveSale.get_go_live_sale_for_sale_ids({})
result[:err].should_not be_blank
result[:err].should == "err1"
end
it "should return all columns corresponding to select field for single go_live_sale" do
go_live_sales = seed_data(1)
sale_ids = go_live_sales.map{ |go_live_sale| go_live_sale.sale_id}
result = GoLiveSale.get_go_live_sale_for_sale_ids({:sale_ids => sale_ids})
result[:err].should be_blank
result[:go_live_sales].count.should_be == 1
delete_seed_data(go_live_sales)
end
it "should return all columns corresponding to select field for multiple go_live_sale" do
go_live_sales = seed_data(2)
sale_ids = go_live_sales.map{ |go_live_sale| go_live_sale.sale_id}
GoLiveSale.get_go_live_sale_for_sale_ids({:sale_ids => sale_ids})
result[:err].should be_blank
result[:message].should be_blank
result[:go_live_sales].count.should == 2
delete_seed_data(go_live_sales)
end
it "should return selected columns corresponding to select field for single go_live_sale" do
go_live_sales = seed_data(1)
sale_ids = go_live_sales.map{ |go_live_sale| go_live_sale.sale_id}
result = GoLiveSale.get_go_live_sale_for_sale_ids({:sale_ids => sale_ids, :columns => ["id","sale_id"]})
result[:err].should be_blank
result[:go_live_sales].count.should_be == 1
delete_seed_data(go_live_sales)
end
it "should return selected columns corresponding to select field for multiple go_live_sale" do
go_live_sales = seed_data(2)
sale_ids = go_live_sales.map{ |go_live_sale| go_live_sale.sale_id}
GoLiveSale.get_go_live_sale_for_sale_ids({:sale_ids => sale_ids, :columns => ["id","sale_id"]})
result[:err].should be_blank
result[:message].should be_blank
result[:go_live_sales].count.should == 2
delete_seed_data(go_live_sales)
end
it "should return error when selecting erroneous columns" do
go_live_sales = seed_data(2)
sale_ids = go_live_sales.map{ |go_live_sale| go_live_sale.sale_id}
GoLiveSale.get_go_live_sale_for_sale_ids({:sale_ids => sale_ids, :columns => ["id","random_sale_id"]})
result[:err].should_not be_blank
delete_seed_data(go_live_sales)
end
end
end
end
def self.delete_seed_data(go_live_sales)
go_live_sales.each do |go_live_sale|
go_live_sale.delete
end
end
def self.seed_data(number_of_go_live_sale_to_create)
go_live_sales =[]
(1..number_of_go_live_sale_to_create).each do |number|
go_live_sales.push(create_go_live_sale(number))
end
return go_live_sales
end
def self.create_go_live_sale(number_to_add)
go_live_sale = GoLiveSale.new
go_live_sale.start_date = Time.now
go_live_sale.sale_id = Sale.select("IFNULL(max(id),0)+#{number_to_add} as sale_id").first.try(:sale_id)
go_live_sale.sale_name = "Test Sale" + go_live_sale.sale_id.to_s
go_live_sale.sale_type = "Flash Sale"+ go_live_sale.sale_id.to_s
User.current_user = User.first
go_live_sale.save
return go_live_sale
end
RSpec::Matchers.define :be_valid do
match_for_should do |actual|
actual[:err].blank?
actual[:validation_error].blank?
actual[:is_valid] == true
end
match_for_should_not do |actual|
actual[:err].present?
actual[:validation_error].present?
actual[:is_valid] == false
end
failure_message_for_should do |actual|
"Expected validation to pass, but it failed"
end
failure_message_for_should_not do |actual|
"Expected validation to fail, but it passed"
end
end
I understand that it is some scope issue or maybe rspec doesn't let you write the tests that way. It will be great if some one can write a small snippet of code explaining how to instantiate test data in such cases. My rails version is 3.0.5.
You can just get rid of the self. in the method definition and move it inside the describe GoLiveSale do block, then call it with seed_data as expected.
For example:
describe GoLiveSale do
def my_method
end
context "some context" do
it "should call my_method" do
expect {my_method}.not_to raise_error
end
end
end
This spec should pass.

Rails: accessing the values of columns selected with column_names

Any ideas what it takes to get this to work? I can't for the life of me figure it out.
def get_prices(c)
#print_prices = {}
Billing.where(:name => c).column_names.each do |d|
if d.match(/^print_/)
#print_prices[d] = d.value
end
end
return #print_prices
end
I've got no idea what to substitute d.value for.
Cheers for any help.
The following code will perform the query, returned in the form of a relation, and reject all items in the attribute key-value hash which do not match the given regex, which, in this case, is /^print_/.
def get_prices(c)
Billing.where(:name => c).first.attributes.reject{ |i| !i.match(/^print_/) }
end
Alternatively, it can also be written as:
def get_prices(c)
Billing.where(:name => c).first.attributes.select{ |i| i.match(/^print_/) }
end

Refactoring controller

As I'm sure you can tell by the following code, I'm a newbie. But I have managed to get this to work correctly...
However, I'd really like to know how to refactor this code, as I'm sure its not the best way to do it. Can anyone point me in the right direction?
Thank you very much in advance...
current_controller = params[:controller]
if current_controller == "menus" && params[:id].present?
#menu = Menu.find(params[:id])
elsif current_controller == "menus" && params[:id].nil?
#menu = Menu.first
elsif current_controller == "items" || current_controller == "categories"
#menu = Menu.find(params[:menu_id])
else
#menu = Menu.last
end
A naive translation into (slightly) smaller code:
current_controller = params[:controller]
#menu = if current_controller == "menus"
params[:id].present? Menu.find(params[:id]) : Menu.first
elsif current_controller == "items" || current_controller == "categories"
Menu.find(params[:menu_id])
else
Menu.last
end
Where does this code live?
Would it make more sense to have this in a base app controller, or filter, etc. and override in the three controllers that are special-cased? Or is this wrapped up in a helper, or...?
Edit Using Procs.
# Default if hash entry not found.
menus = Hash.new(Proc.new { |p| Menu.last })
# Items and categories controllers
itemcats = Proc.new { |p| Menu.find(p[:menu_id]) }
menus["items"] = menus["categories"] = itemcats
# Menus controller
menus["menus"] = Proc.new { |p| p[:id] ? Menu.find(p[:id]) : Menu.first }
#menu = menus[params[:controller]].call(params)
(More or less.)
This would be my refactoring to your code:
#menu = case controller.controller_name
when "menus"
if params[:id]
Menu.find(params[:id])
else
Menu.first
end
when "items" || "categories"
Menu.find(params[:menu_id])
else
Menu.last
end
This is untested, but you could try using the case statement as davenewton said
# Case on an expression:
#menus = case params[:controller]
when "menus" && params[:id].present? then Menu.find(params[:id])
when "menus" && params[:id].nil? then Menu.first
when "items", "categories" then Menu.find(params[:menu_id])
else Menu.last
end
You can replace the "then's" with semicolons if you prefer

Rails 3 and validating if http is included in link

When a user submits a link, is there a way to validate if he have included the http:// or not. I other words, is it possible to not only validate but also add the http:// if it is missing?
I am using Rails 3.
You could override the setter method for the link. In your model, something like this:
def link=(str)
str = 'http://' + str if str[0,7] != 'http://'
super(str)
end
This would force adding http:// to the start of all links if not already there.
You can use a custom validation.
Pretending your model is "Post" and the attribute is "url" you can use something like:
class Post < ActiveRecord::Base
validate :ensure_valid_url
protected
def ensure_valid_url
protocol_regexp = %r{
\A
(https?://)
.*
\Z
}iux
self.url = "http://" + url unless url.blank? or url.match(protocol_regexp)
ipv4_part = /\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]/ # 0-255
regexp = %r{
\A
https?://
([^\s:#]+:[^\s:#]*#)?
( (xn--)?[[:alnum:]\w_]+([-.][[:alnum:]\w_]+)*\.[a-z]{2,6}\.? |
#{ipv4_part}(\.#{ipv4_part}){3} )
(:\d{1,5})?
([/?]\S*)?
\Z
}iux
default_message = 'does not appear to be a valid URL'
default_message_url = 'does not appear to be valid'
options = { :allow_nil => false,
:allow_blank => false,
:with => regexp }
message = url.to_s.match(/(_|\b)URL(_|\b)/i) ? default_message_url : default_message
validates_format_of(:url, { :message => message }.merge(options))
end
end
This example is based on validates_url_format_of
variation on Steve Lorek's answer taking in the account that some links submitted by user will contain https:// instead of http://
def link=(str)
str = 'http://' + str if (str[0,7] != 'http://' && str[0,8] != 'https://')
super(str)
end