How can I randomize DataMapper collection and convert it to JSON? - sql

I'm pulling my hair out trying to build a little random photo JSON feed using DataMapper/Sinatra. Here's what I have so far..
Photo.favorites.to_json(:methods => [:foo, :bar])
So that works fine. The to_json method is provided in the dm-serializer library. All I want to do is randomize that feed so the photos don't show up in the same order every time. Since DataMapper doesn't have built-in support for random selects, I tried sorting the results, but to_json gets mad because the sort_by turns the DataMapper::Collection into an Array..
Photo.favorites.sort_by{rand}.to_json(:methods => [:foo, :bar])
# wrong argument type Hash (expected Data)
I searched for that error and saw a lot of Rails-related stuff about ActiveRecord and conflicts between competing to_json methods, but nothing really about DataMapper. A lot of people recommended using json_pure instead of the json gem, so I gave that a try by adding require 'json/pure' to my Sinatra app. Now the query above gives me this error instead..
Photo.favorites.sort_by{rand}.to_json(:methods => [:foo, :bar])
# undefined method `[]' for #<JSON::Pure::Generator::State:0x106499880>
I also tried doing the randomization with straight SQL:
def self.random
repository(:default).adapter.query('SELECT * FROM photos WHERE favorite = 1 ORDER BY RAND();')
end
But that doesn't really work for me because it returns Struct objects with attributes, rather than instances of the actual Photo class. This means I can't leverage the handy to_json arguments like :methods.
Lastly I tried using find_by_sql, but I guess the method's been removed from DataMapper?
def self.random
find_by_sql("SELECT * FROM `photos` ORDER BY RAND();")
end
# undefined method `find_by_sql' for Photo:Class
Sheesh! Any thoughts on how to resolve this?

The find_by_sql method was moved to the dm-ar-finders plugin.

Related

How do I get the results of the Plucky Query inside my controller?

I'm missing something simple - I do not want to access the results of this query in a view.
Here is the query:
#adm = Admin.where({:id => {"$ne" => params[:id].to_s},:email => params[:email]})
And of course when you inspect you get:
#adm is #<MongoMapper::Plugins::Querying::DecoratedPluckyQuery:0x007fb4be99acd0>
I understand (from asking the MM guys) why this is the case - they wished to delay the results of the actual query as long as possible, and only get a representation of the query object until we render (in a view!).
But what I'm trying to ascertain in my code is IF one of my params matches or doesn't match the result of my query in the controller so I can either return an error message or proceed.
Normally in a view I'm going to do:
#adm.id
To get the BSON out of this. When you try this on the Decorated Query of course it fails:
NoMethodError (undefined method `id' for #<MongoMapper::Plugins::Querying::DecoratedPluckyQuery:0x007fb4b9e9f118>)
This is because it's not actually a Ruby Object yet, it's still the query proxy.
Now I'm fundamentally missing something because I never read a "getting started with Ruby" guide - I just smashed my way in here and learned through brute-force. So, what method do I call to get the results of the Plucky Query?
The field #adm is set to a query as you've seen. So, to access the results, you'll need to trigger execution of the query. There are a variety of activation methods you can call, including all, first, and last. There's a little documentation here.
In this case, you could do something like:
adm_query = Admin.where({:id => {"$ne" => params[:id].to_s},:email => params[:email]})
#adm_user = adm_query.first
That would return you the first user and after checking for nil
if #adm_user.nil?
# do something if no results were found
end
You could also limit the query results:
adm_query = Admin.where( ... your query ...).limit(1)

Possible to use ActiveRecord methods against AR collections?

I would like to be able to pull all records from the db:
u = User.all
And then once loaded be able to apply AR methods to the resulting collection:
u.first
Is this possible in rails?
Once you actually query the database, the results become an array instead of an ActiveRecord::Relation. (Though #first would still work fine, since it's a method that also exists on Array).
If you just need a starting point to build an ActiveRecord::Relation though, you can use scoped:
# Doesn't execute a query yet
u = User.scoped
# This now executes a query similar to SELECT * FROM users LIMIT 1
u.first
Note that in Rails 4.0, #all now does the same thing as #scoped (whereas in Rails 3, it returns an array).
Why don't you try it?
User.all doesn't return an AR collection it returns an Array. Get rid of the .all and you will have a working example.

Rails 3 Symbol.gte method

I saw the following code example:
Subscription.where(:created_at.gte => t0)`
To me, this seems a little more ruby/rails-like as opposed to:
Subscription.where("created_at > ?", t0)`
However, attempting to reproduce this in my own code on results in:
undefined method `gte' for :created_at:Symbol
I'm not certain, but I believe this is a MongoDB method. If so is there any way I can extend ActiveRecord to make use of it?
You are correct. This is mongoid query DSL.
Similar way to extend ActiveRecord is achieved using squeel gem. However, it is slightly different.
Subscription.where{ created_at.gte => t0 }
Notice different brackets and created_at is not a symbol.

mongoid query - calling the size method produces an error

When I execute this query:
User.where(:comments.size => 10)
I am getting the following error:
undefined method `size' for :comments:Symbol
But according to the documentation here:
http://mongoid.org/docs/querying/criteria.html
This should be possible. So, why the error?
Note: 'comments' is separate collection from User with a 'has_and_belongs_to_many' relationship.
I am using mongoid 3.0.0 and bson_ext 1.6.1
Thanks in advance!
This will work if User embeds Comments but not when you relate User to Comments. It works for embedding because of the $size operator (although, this is not a super efficient query to perform. Better to cache the size in a separate field).
Use with_size, not size, with Mongoid 3. It will translate to the MongoDB $size operator.
Queryable#with_size: Add $size selection. Matches documents who's array field has the exact size of the provided value. This is named with_size not to conflict with Ruby's Enumerable#size or Symbol#size." (from the Origin Selection documentation)

Rails3 Kaminari undefined with .all

Hi
I wonder how to work around the problem I have with the pagination gem "Kaminari".
For what I've understood you cant paginate #user = User.all.page(5)?
But what if I have this code and want to paginate that, is it possible or do I need to change the code?
#price = Price.joins(:retailer, :retailer => :profile).
where(['product_id=? AND size_id=?', params[:prod_id], params[:si_id]]).
group(:retailer_id).order("SUM((prices.price * #{params[:amount].to_i}) + profiles.shippingCost)").all
The only thing I receive right now when applying.page(5) to that code is
undefined method `page' for #<Class:0x000001023c4558>
You don't need the .all because the joins call, along with where and group, is returning an array of objects for you that meet your criteria. Remove your .all and call page on the instance variable (which you might want to rename to #pages or something else plural).