rails activerecord expanding the dataset to include joineddata - ruby-on-rails-3

We're trying to use json to pass marker data to google maps.
Up till now we were just pulling the dataset we needed (which dont include coordinates), and then extracting the coordinates the view using a belongs_to relationship. eg:
controller:
#clubs = Clubs.all
view:
#clubs.each do |club|
lng = club.town.longitude
lat = club.town.latitude
end
Now we want to pull the data through json. This means that the belongs_to is no-longer available in the view, so we need to append the long and lat data to the json #clubs dataset inside the controller so that we are able to do:
#clubs.each do |club|
lng = club.longitude
lat = club.latitude
end
How do we do this, or is there another way we can get round this problem?
Thanks!

You can include 'town' association in club:
club.as_json(:include => :town)

Related

Get all data using CActiveDataProvider

I have a model InboxMessageHelper with relations like
'message', 'sender' and 'receiver' and I am using the following criteria to query data:
$model = new CActiveDataProvider('IndividualMessageHelper', array(
'criteria'=>array(
'condition'=>'receiver_id = '.Yii::app()->user->id,
'order'=>'message.created_at DESC',
'with'=>array('message', 'sender', 'receiver'),
'together'=>true,
),
));
I want to get all data (i.e. including the relations data) inside the controller and form a JSON, but the problem is that i cannot access related fields data. I can see that the data is available when I use
CVarDumper::dump()
when I try to encode $model->data then only data from current table gets encoded. How should I go about it?
I don't think CActiveDataProvider can be used in this way. You need to be working with the model. So you'll need something like this in your controller.
$models = IndividualMessageHelper::model()->findAll('receiver_id = '.Yii::app()->user->id);
foreach($models as $model){
$json[] = $model->getAttributes; //This won't get any model properties you've declared
yourself, only database columns
}
//Now get the related records and add them to the array.
array_push($json, $model->getRelated('message')->getAttributes());
array_push($json, $model->getRelated('sender')->getAttributes());
array_push($json, $model->getRelated('receiver')->getAttributes());
echo json_encode($json);

MongoDB-Rails: insert a json into db using mongomapper and retriving it

I am completely new to Rails and MongoDB. I am using Rails-3 and MongoDB with MongoMapper to create a small application which stores some data and returns the data in json format. The client expects the json in a particular format. But I am not able to create the same format in the saved document.
Reqd Format:
{"Name":"ABC","max":{"key":"KEY-1","value":"100"},"min":{"key":"KEY-2","value":"0"}}
Parent Doc
class Story
include MongoMapper::Document
key :item, String
key :max,
key :min,
end
What I want is to create a document {"key":"KEY-1","value":"100"} first and then map that document to the parent document's max key and similarly another document to the min key.
I tried many ways, but I am not able to make it work.
Also,
The I want to remove the field id (object id) from the response JSON while returning to the client.
Sample JSON:
{"id":"51e64bce44ae8bf1fea3f78f","text":"Text 1","value":"Value 1"}
How can i do that?
Update
Answering one of my own question : "Removing the non-required fields from the json response"
It can be done by defining the as_json method inside the Model class. This will add only the fields 'key' and 'value' to the generated json.
def as_json(options={}){
:key =>self.key,
:value => self.value
}
Answering to my own question:
I searched around and couldn't find any satisfactory answer for my question.
On a temporary basis, I had created hash for the inner class and was assigning the value. This was a temporary solution which is little dirty.
I had posted the same question to a mongomapper group and got the answer. Sharing that answer here..
Assume that I have a model called Inner and another called Outer
one :max, :class_name => Inner
This will embed the Inner class object to the max attribute of the Outer class

Query data from two associated tables

For my app:
user has_many images, image belongs_to user
image has_one location, location belongs_to image
Perhaps the location's fields should just be part of the image. But regardless, I'm trying to write this query in Rails:
SELECT image.caption, location.latitude, location.longitude
FROM image, location
WHERE location.image_id = image.id
AND image.user_id = 5
or alternatively, if it's easier:
SELECT image.*, location.*
FROM image, location
WHERE location.image_id = image.id
AND image.user_id = 5
How would I write this as an ActiveRecord query?
I think you want to read about Eager Loading Associations.
#images = Image.includes(:location).where("images.user_id = ?", 5)
This will find Image instances where user_id = 5. It then runs a 2nd query that will JOIN and build the associated Location instance (thats what the .includes(:location) will do for you).
This more closely matches your alternative query, as it does select all columns from images and location tables.
You can build an Array based on this containing a hash with only the keys you're interested in through something like this.
#hash_object = #images.collect { |i| { caption: i.caption, latitude: i.location.latitude, longitude: i.location.longitude } }
If you want to build this with only a single query, you can use .joins(:location) in combination with .includes(:location)
Image.joins(:location).includes(:location).where("images.user_id = ?", 5)
Important: This will omit Image instances who have no assoicated Location. You can modify the joins() a bit to help with this, but the above will have this omission.
If you really want only specific columns to be selected, read up on Selecting Specific Columns though there are warnings for the use of this
If the select method is used, all the returning objects will be read only.
and
Be careful because this also means you’re initializing a model object with only the fields that you’ve selected.
In Rails master (not out in 3.2.11) you can pass multiple columns to .pluck() but this appears to only be restricted to a single table (you wouldn't be able to get the locations table's :latitude and :longitude when plucking from Image). It's good to know about though.

Once a store is registered, automatically creating a landmark on Google Maps

I am trying to have a store register with their address, which once registered will automatically create a landmark on google maps of the location. How should I go about doing this? I have been using Ruby on Rails for the majority on
Geokit is fairly easy to implement. If you are just beginning to use the Google mapping API, I would recommend starting here: https://github.com/jlecour/geokit-rails3.
Once you get it setup properly, you can do something like this in your controller...
#event = Event.find(params[:id])
if #event.is_geocoded?
#map = GMap.new("map_div", 'map')
#map.control_init(:large_map => true, :map_type => false)
#map.center_zoom_init(#event.latlon,12)
#map.overlay_init(GMarker.new(#event.latlon, :title => #event.name, :info_window => #event.address_for_map_popup))
end
In your view, something like this:
- if #map
- initialize_map
= #map.to_html.html_safe
= #map.div(:width => 478, :height => 400).html_safe
It is the GMarker that creates the map marker and overlay_init that overlays it on top of the map.
So the best way would probably be to store their location in a database (or translate to coordinates first then store in database). From there you can use something like google maps javascript api to drop pins onto a map you generate.
http://code.google.com/apis/maps/documentation/javascript/

Mapped two arrays... now... can i map three?

This mapping worked:
#fbc = FbComments.where("reviewee_id = ?", current_user.id)
#users = User.order("last_name")
#fb_comments = #fbc.map! { |fb| [fb, #users.find_by_id(fb.user_id)] }
So two arrays are mapped... one with comments and one with the user data of the person that made the comments. But I also need the user's profile picture data. Do i change the original mapping method to include a third array somehow (e.g. #fbc + #users + #pictures), or do i have to map another array on the result of mapping the first two (e.g. #fb_comments + #pictures)?
Profile pictures, like comments, have a user_id that is matched to the id of the user who made the comments.
Thanks.
I'm not sure why you're doing this the way you are. Why not use a join (.includes) to get everything in one query?
#fbc = FbComments.where("reviewee_id = ?", current_user.id).includes(:user => :picture)
#fbc.first.user # => The first user in the results
#fbc.first.user.picture # => The first user's picture
(I'm assuming here that profile picture data is its own model called Picture. Change it to fit your app if necessary.)
Take a look at the documentation and scroll down to "Eager loading of associations."