Ruby: How to get array instead of DataMapper::Collection in query result - ruby

here is my code:
today_ids_from_db = Rating.all(:fields => 'my_id', :ts_d => Time.now)
today_ids_from_db.class == DataMapper::Collection
but I need to get simple ruby array with my_id values
how to achieve this?

You can also try out this Activerecord beauty called pluck
Rating.where(:ts_d => Time.now).pluck(:my_id)

Try this code
Rating.all(:ts_d => Time.now).map(&:my_id)

Related

How to use valid? method on an array in rails 3

I am working on an app in rails 3.
I have several records that i want to save to my database. I am trying to make sure that all the objects in an array (the records are stored in an array) are valid before saving. The Owner model validates the presence of name and email. In the rails console, I have tried the following:
#owner = Array.new
=> []
#owner[0] = Owner.new (name:"peter", email:"peter#gmail.com")
=> returns object
#owner[1] = Owner.new (name:"fred", email:"fred#gmail.com")
=> returns object
#owner[2] = Owner.new (name:"", email:"")
=> returns object
#owner[0].valid?
=> true
#owner[1].valid?
=> true
#owner[2].valid?
=> false
#owner.each { |t| t.valid? }
=> returns an array like this: [object1, object2, object3]. I would expect something like this instead: [true,true,false]
I dont understand why the .valid? method works fine if I individually check the elements of the array using #owner[i], but doesnt work correctly if I'm using .each to iterate through the array. Anybody know what might be the problem?
What I am trying to do is achieve something like this:
(#owner.each { |t| t.valid? }).all?
To make sure that each record is valid, then I can proceed to save them.
Thanks
Each does not return an array of valid? values. You probably want either:
(#owner.collect { |t| t.valid? }).all?
or
(#owner.all? { |t| t.valid? })
The examples can also be written as:
#owner.collect(&:valid?).all?
or
#owner.all?(&:valid?)

How to get raw Mongo data results from a MongoMapper Plucky::Query object?

Let's say we have a MongoDB collection called "images", and a MongoMapper-powered application with a corresponding "Image" model. If we set up a MongoMapper query using this model, we see that it is of type Plucky::Query and returns results of type Image:
>> Image.where(:file_type => 'image/jpeg').class
=> Plucky::Query
>> Image.where(:file_type => 'image/jpeg').first.class
=> Image
We can run the corresponding query directly on the Mongo adapter, mostly bypassing MongoMapper, by accessing the MongoMapper.connection. If we do it this way, the query is of type Mongo::Cursor and returns raw data results of type BSON::OrderedHash:
>> MongoMapper.connection.db(dbname).collection('images').find({ :file_type => 'image/jpeg' }).class
=> Mongo::Cursor
>> MongoMapper.connection.db(dbname).collection('images').find({ :file_type => 'image/jpeg' }).first.class
=> BSON::OrderedHash
The question is, is there a way to take a Plucky::Query like above and convert it to (or retrieve from it) a basic, non-extended Mongo::Cursor object?
At first I thought I found a solution with find_each, which does actually take a Plucky::Query and return a Mongo::Cursor:
>> Image.where(:file_type => 'image/jpeg').find_each.class
=> Mongo::Cursor
But it turns out this Mongo::Cursor is somehow extended or otherwise different from the above one because it still returns Image objects instead of BSON::OrderHash objects:
>> Image.where(:file_type => 'image/jpeg').find_each.first.class
=> Image
Update: I can't simply bypass MongoMapper query magic altogether like I did in the second case because I need to access features of MongoMapper (specifically named scopes) to build up the query, so what I end up with is a Plucky::Query. But then I want the results to be plain data objects, not models, because all I need is data and I don't want the overhead of model instantiation.
If you drop to the driver, the transformer is nil by default:
1.9.3p194 :003 > Image.collection.find({ :file_type => 'image/jpeg' }, { :limit => 1 }).first.class
=> BSON::OrderedHash
MongoMapper achieves the conversion by setting a "transformer" lambda on the plucky query. You can see this in the MongoMapper source code:
def query(options={})
query = Plucky::Query.new(collection, :transformer => transformer)
...
end
...
def transformer
#transformer ||= lambda { |doc| load(doc) }
end
So after each mongo document retrieval, this Plucky::Query runs the transformation that loads the model. Looking at the Plucky source code we see that there is a simple setter method [] we can use to disable this. So this is the solution:
plucky_query = Image.where(:file_type => 'image/jpeg')
plucky_query.first.class
# => Image
plucky_query[:transformer] = nil
plucky_query.first.class
# => BSON::OrderedHash
If you don't mind monkey-patching you can encapsulate like so:
module Plucky
class Query
def raw_data
self[:transformer] = nil
self
end
end
end
Then you could simply write:
Image.where(:file_type => 'image/jpeg').raw_data.first.class
# => BSON::OrderedHash

How to use DataMapper `NOT LIKE` clause?

I'm using DataMapper in a Sinatra project. I'd like to be able to use a NOT LIKE stament in a DataMapper finder method, but cannot figure out how to do so.
One might imagine that this would work:
#people = People.all(:female => 1, :name.like.not => '%julie%')
...but DataMapper throws an error. Switching the order of not and like doesn't help.
Any way around this?
According to the docs you can use subtraction to produce NOT queries:
# Subtraction produces a NOT query
Zoo.all(:state => 'IL') - Zoo.all(:tiger_count.gte => 5)
# in SQL => SELECT * FROM "zoos" WHERE
# ("state" = 'IL' AND NOT("tiger_count" >= 5))
Therefore the answer would seem to be:
#people = People.all(:female => 1) - People.all(:name.like => '%julie%')

Trying to call find_by_id on ActiveRecord::Relation, Arel exception

I'm getting to grips with Rails 3 and I can't seem to do a basic find from a result set. My code looks like the following:
#project =
#user.where({:projects => {:project_member_id => user.id}}).find_by_id(params[:id])
I understand that the "where" section will not return a collection but merely create a query that is waiting to be run against the db. However, I can't understand why I get the following error when I try to run the find_by_id:
undefined method `to_sql' for #<Arel::Attributes::String:0x106d9ecf0>
Can somebody point out where I'm going wrong please?
May be you can write something like this:
#project =
#user.where({:projects => {:project_member_id => user.id}}).where(:id => params[:id])
I think it will works.
Alex.
I could be misunderstanding what you are trying to do here, but it looks like you have an association called projects in the user model, right? If so, this is much simpler (and works):
#project = #user.projects.find params[:id]
If you don't have an association setup, you should look into them. There is a great rails guide here on the subject.
I hope this helps.
As you mentioned above, "where" would return ActiveRecord::Relation object, you can check it by running:
#project =
#user.where({:projects => {:project_member_id => user.id}}).class
In order to return a collection of instantiated objects and run find, you can try to force it by running something like:
#project =
#user.where({:projects => {:project_member_id => user.id}}).all.find_by_id(params[:id])
Love method chaining in Rails!
However, this would first find all projects with passed uesr.id (which can be costly, and, probably not what you want)...
Good luck!
Try
#project =
#user.where({:projects => {:project_member_id => user.id}}).where(:id => params[:id]).first
But I dont understand why you are doing all these when you have the primary key with you..just Model.find params[:id] is enough I think (I assume there is something more to it).
Try this:
#project = #user.where({:projects => {:project_member_id => user.id}}).all.find {|p| p.id == params[:id]}

Preventing SQL Injection/Good Ruby method

What is a good method in Ruby to prevent SQL Injection?
in straight up ruby? use prepared statements:
require 'mysql'
db = Mysql.new('localhost', 'user', 'password', 'database')
statement = db.prepare "SELECT * FROM table WHERE field = ?"
statement.execute 'value'
statement.fetch
statement.close
Not just in Ruby - bind your parameters (be it in the database, or in your client code).
Check out the guide they have up on this: http://guides.rubyonrails.org/security.html#injection
Basically, you want to use bind variables in your models to find data, rather than inline parameters..
Model.find(:first, :conditions => ["login = ? AND password = ?", entered_user_name, entered_password])
According to http://ruby.railstutorial.org/ you can prevent Cross Site Request Forgery by inserting the
<%= csrf_meta_tags %>
tag in the header of app/views/layouts/application.html.erb.
Direct link of example
This thread references:
http://www.ruby-forum.com/topic/90258#new
http://www.ruby-forum.com/topic/82349#143790
ActiveRecord's find() method has built in ways to avoid SQL injection by
using the format
> :conditions => [ "user_name = ?", user_name]
Is there any such system for escaping injection in order? It seems to
only take a string and feed it to the SQL statement. This causes a
vulnerability when using params to set : order as in this function:
def list
sort_by = params[:sort_by]
#book_pages, #books = paginate :books,
:order => sort_by,
:per_page => 10
end
We've tried a few methods to sanitize sort_by such as order => ['?',
sort_by] but it just passes that to the SQL statement like a flattened
array. The 'escaping magic' does not work for order. Should I use
gsub! to sanitize params[:sort_by]?

Resources