Rails placeholder when building array - ruby-on-rails

I am trying to do this:
query << ["AND f.name LIKE '%:last_name%' ", :last_name => params[:last_name] ]
But getting an error. Surely the syntax is incorrect.
Does anyone know how to do it?

Is this an array or an hash? the first item looks like an array and the second like a hash. Without some context it is hard to tell. You can start by maybe trying this:
["AND f.name LIKE '%:last_name%' ", {:last_name => params[:last_name]} ]

Where query is an array you may want to pass a string so you don't end up with an array of arrays, you could do this:
Rails 3
query << "AND f.name LIKE '%#{params[:last_name]}%' "
Rails 2
last_name = ActionController::Base.helpers.sanitize(params[:last_name])
query << "AND f.name LIKE '%#{last_name}%' "

since you're not using rails 3, you should use scoped to chain queries
records = Record.scoped(:conditions => { :active => true })
records = records.scoped(:conditions => ["records.name LIKE '%:last_name%' ", { :last_name => params[:last_name] }])
so you don't have to build queries like that.

Related

Change ruby hash to jsonl - JSON seperated by newlines

I am looking at posting to an endpoint on Bubble.io using Ruby and they require jsonl (plain text, new-line seperated) instead of JSON.
Is there a way to take a hash and make it jsonl? Something like hash.to_jsonl.
For jsonl (or ndjson), the json need to be formated as single line.
Therefor use to_json method.
require 'json'
group = [{:name => "Tom", :age => 27}, {:name => "Jerry", :age => 37}]
puts group.map { |r| JSON.generate(r) }.join("\n")
This code generates the following:
{"name":"Tom","age":27}
{"name":"Jerry","age":37}
Here is the solution I went with:
group = [{name => "Tom"}, {name => "Jerry"}]
generated = []
group.each do |r|
generated << JSON.generate(r)
end
jsonl_text = generated.join("\n")

SQL-like syntax for array of objects

I have an array of objects. I need to use an SQL-like condition WHERE field like '%value%' for some object fields in this array.
How to do it?
Edited:
For example I have array with Users and I need to find all users with first_name like ike and email like 123.
Edited2:
I need method to get Users with first_name like smth and email like smth from ARRAY of my Users. Users have first_name and email.
Edited3:
All my users are in database. But I have some business logic, at the end of this logic I have array with Users. Next I need to filter this array with some text: ike for first_name and 123 for email. How to do it?
arr = %w[hello quick bool boo foo]
arr.select { |x| x.include?("foo") }
=> ["bool", "boo", "foo"]
or in your case, if you have an array of objects, you can do:
x.first_name.include?("foo") && x.email.include?("123")
For more customization, you can use Array#select with Regexeps
If you can just use ruby methods for this that do something like this:
User = Struct.new(:email, :first_name) # Just creating a cheap User class here
users = [
User.new('1#a.com' , 'ike'),
User.new('123#a.com', 'bob'),
User.new('123#a.com', 'ike'),
]
# results will be an array holding only the last element in users
results = users.find_all do |user|
user.email =~ /123/ and
user.first_name =~ /ike/
end
Writing your own sql parser seems like a pretty bad idea, but if you really need to parse simple SQL where clauses you could do something like this:
User = Struct.new(:email, :first_name) # Just creating a cheap User class here
users = [
User.new('1#a.com' , 'ike'),
User.new('123#a.com', 'bob'),
User.new('123#a.com', 'ike'),
]
def where(array, sql)
sql = sql.gsub(/\s+AND\s+/, ' ') # remove AND's
terms = Hash[ *sql.split(/\s+LIKE\s+| /) ] # turn "a LIKE 'b'" into {'a': "'b'"}
array.find_all do |item|
terms.all? do |attribute, matcher|
matcher = matcher.gsub('%', '.*') # convert %
matcher = matcher.gsub(/^['"]|["']$/, '') # strip quotes
item.send(attribute) =~ /^#{matcher}$/
end
end
end
# results will be an array holding only the last element in users
results = where(users, "first_name LIKE '%ike%' AND email LIKE '%123%'")
This will only work for where clauses what only contain LIKE statements connected by AND's. Adding support for all valid SQL is left as an exercise for the reader, (or better yet, just left alone).
I've built a ruby gem uber_array to enable sql-like syntax for arrays of Hashes or Objects you might want to try.
require 'uber_array'
# Array of Hash elements with strings as keys
items = [
{ 'name' => 'Jack', 'score' => 999, 'active' => false },
{ 'name' => 'Jake', 'score' => 888, 'active' => true },
{ 'name' => 'John', 'score' => 777, 'active' => true }
]
uber_items = UberArray.new(items)
uber_items.where('name' => 'John')
uber_items.where('name' => /Ja/i)
uber_items.like('ja')
uber_items.where('name' => %w(Dave John Tom))
uber_items.where('score' => 999)
uber_items.where('score' => ->(s){s > 900})
uber_items.where('active' => true, 'score' => 800..900)

Building a Mongo query using rails? How?

This is how I went about to query for one specific element.
results << read_db.collection("users").find(:created_at => {:$gt => initial_date}).to_a
Now, I am trying to query by more than one.
db.inventory.find({ $and: [ { price: 1.99 }, { qty: { $lt: 20 } }, { sale: true } ] } )
Now how do I build up my query? Essentially I will have have a bunch of if statements, if true, i want to extend my query. I heard there is a .extend command in another langue, is there something similar in ruby?
Essentially i want to do this:
if price
query = "{ price: 1.99 }"
end
if qty
query = query + "{ qty: { $lt: 20 } }"
end
and than just have
db.inventory.find({ $and: [query]})
This syntax is wrong, what is the best way to go about doing this?
You want to end up with something like this:
db.inventory.find({ :$and => some_array_of_mongodb_queries})
Note that I've switched to the hashrocket syntax, you can't use the JavaScript notation with symbols that aren't labels. The value for :$and should be an array of individual queries, not an array of strings; so you should build an array:
parts = [ ]
parts.push(:price => 1.99) if(price)
query.push(:qty => { :$lt => 20 }) if(qty)
#...
db.inventory.find(:$and => parts)
BTW, you might run into some floating point problems with :price => 1.99, you should probably use an integer for that and work in cents instead of dollars. Some sort of check that parts isn't empty might be a good idea too.

How to insert multiple records into database

How can I insert multiple records into a database using rails syntax.
INSERT INTO users (email,name) VALUES ('a#ao.in','a'),('b#ao.in','b'),
('c#ao.in','c');
This is how we do it in MySQL. How is this done in Rails?
Check out this blog post: http://www.igvita.com/2007/07/11/efficient-updates-data-import-in-rails/
widgets = [ Widget.new(:title => 'gizmo', :price => 5),
Widget.new(:title => 'super-gizmo', :price => 10)]
Widget.import widgets
Depending on your version of rails, use activerecord-import 0.2.6 (for Rails 3) and ar-extensions 0.9.4 (for Rails 2)
From the author: http://www.continuousthinking.com/tags/arext
While you cannot get the exact SQL that you have there, you can insert multiple records by passing create or new on an array of hashes:
new_records = [
{:column => 'value', :column2 => 'value'},
{:column => 'value', :column2 => 'value'}
]
MyModel.create(new_records)
I use following in my project but it is not proper for sql injection.
if you are not using user input in this query it may work for you
user_string = " ('a#ao.in','a'), ('b#ao.in','b')"
User.connection.insert("INSERT INTO users (email, name) VALUES"+user_string)
Just a use activerecord-import gem for rails 3 or ar-extensions for rails 2
https://github.com/zdennis/activerecord-import/wiki
In Gemfile:
gem "activerecord-import"
In model:
import "activerecord-import"
In controller:
books = []
10.times do |i|
books << Book.new(:name => "book #{i}")
end
Book.import books
This code import 10 records by one query ;)
or
##messages = ActiveSupport::JSON.decode(#content)
#messages = JSON(#content)
#prepare data for insert by one insert
fields = [:field1, :field2]
items = []
#messages.each do |m|
items << [m["field1"], m["field2"]]
end
Message.import fields, items
You can use Fast Seeder to do multiple insert.
In People_controller.rb
# POST people
NAMES = ["Sokly","Nary","Mealea"]
def create
Person.transaction do
NAMES.each do |name|
#name = Person.create(:name => name)
#name.save
end
end
end
Just pass an array of hashs to the create method like this:
User.create([{:email => "foo#com", :name => "foo"}, {:email => "bar#com", :name => "bar"}])

How can I pass multiple attributes to find_or_create_by in Rails 3?

I want to use find_or_create_by, but this statement does NOT work. It does not "find" or "create" with the other attributes.
productproperty = ProductProperty.find_or_create_by_product_id(:product_id => product.id, :property_id => property.id, :value => d[descname])
There seems to be very little, or no, information on the use of dynamic finders in Rails 3. "and"-ing these together gives me a an unknown method error.
UPDATE:
Originally I couldn't get the following to work. Please assume I'm not an idiot and "product" is an instance of Product AR model.
product.product_properties.find_or_create_by_property_id_and_value(:property_id => 1, :value => "X")
The error methods was:
no such keys: property_id, value
I couldn't figure that out. Only this morning did I find the reference to passing the values like this instead:
product.product_properties.find_or_create_by_property_id_and_value(1, "X")
And voilá, it works fine. I would have expected a hash to work in the same situation but I guess not.
So I guess you get a down vote if you miss something on the internet?
If you want to search by multiple attributes, you can use "and" to append them. For example:
productproperty = ProductProperty.find_or_create_by_product_id_and_property_id_and_value(:product_id => product.id, :property_id => property.id, :value => d[descname])
There is one minor catch to be aware of. It will always return the object you've specified, even if that object can't be saved due to validation errors. So make sure you check to see if the returned object has an id (or is_valid?). Don't assume its in the database.
Alternatively, you can use the 'bang' version of the method to raise an error if the object cannot be saved:
http://guides.rubyonrails.org/active_record_querying.html#find-or-create-by-bang
This applies to Rails 3.
See http://api.rubyonrails.org/classes/ActiveRecord/Base.html:
With single query parameter:
productproperty = ProductProperty.find_or_create_by_product_id(product.id) { |u| u.property_id => property_id, u.value => d[descname] } )
or extended with multiple parameters:
productproperty = ProductProperty.find_or_create_by_product_id(:product_id => product.id, :property_id => property_id, :value => d[descname]) { |u| u.property_id => property_id, u.value => d[descname] } )
Would work with:
conditions = { :product_id => product.id,
:property_id => property.id,
:value => d[descname] }
pp = ProductProperty.find(:first, :conditions => conditions) || ProductProperty.create(conditions)
In Rails 4, you can use find_or_create_by(attr1: 1, attr2: 2) to find or create by multiple attributes.
You can also do something like:
User.create_with(
password: 'secret',
password_confirmation: 'secret',
confirmation_date: DateTime.now
).find_or_create_by(
email: 'admin#domain.com',
admin: true
)
If you need to create the user with some attributes, but cannot search by those attributes.
You could also use where(...).first_or_create - ActiveRecord::Relation#first_or_create.
product_property_attrs = { product_id: product.id,
property_id: property.id,
value: d[descname] }
product_property = ProductProperty.where(product_property_attrs).first_or_create
I've found in Rails 3.1 you do not need to pass the attributes in as a hash. You just pass the values themselves.
ProductProperty.find_or_create_by_product_id_and_property_id_and_value(
product.id, property.id, d[descname])

Resources