In my events_controller, if I use the following:
def index
respond_with(#market.events) do |format|
format.js {render :json => #market.events, :callback => params[:callback]}
end
end
I get the expected response. Events is a nested resource under markets.
But I need to also return the asset associated with the event, which is in a related table. If I try the following:
respond_with(#market.events.joins #market.events.assets) do |format|
I get undefined method `assets' for #ActiveRecord::Relation:0x1088215a0. On my events show page, I can do asset.asset.url and it shows.
Any ideas on where I've gone wrong?
There are multiple events, and you're trying to call assets on the collection of events—that is, a set of many events, which doesn't have assets, though each element in the collection has assets.
You say you want to get the asset (singular) for the event (also singular), so I'm not really sure what you actually want to achieve here, since you're returning multiple assets. To get all the assets for all the events you can do:
#market.events.map(&:assets).flatten # If event has many assets
#market.events.map(&:asset) # If event has one asset
Have you tried eager loading ? With #market.events.includes(:assets), you should have the assets too.
Related
I have a code section like the following:
users = User.all(:fname => "Paul")
This of course results in getting all users called "Paul". Now I only need some of the columns available for each user which leads to replacing the above line by something like this:
users = User.all(:name => "Paul", :fields => [:id, :fname, :lname, :email])
Until now everything works as expected. Unfortunately now I want to work with users but as soon as I use something like users.to_json, also the other columns available will be lazy-loaded even due the fact, that I don't need those. What's the correct or at least a good way to end up with users only containing the attributes for each user that I need?
An intermediate object like suggested in How to stop DataMapper from double query when limiting columns/fields? is not a very good option as I have a lot of places where would need to define at least twice which fields I need and also I would loose the speed improvement gained by loading only the needed data from the DB. In addition such an intermediate object also seems to be quite ugly to build when having multiple rows of the DB selected (=> multiple objects in a collection) instead of just one.
If you usually works with the collection using json I suggest overriding the as_json method in your model:
def as_json(options = nil)
# this example ignores the user's options
super({:only => [:fname]}.merge(options || {}))
end
You are able to find more detailed explanation here http://robots.thoughtbot.com/better-serialization-less-as-json
I want to get specific document attributes and exclude the _ids. This is my controller action:
def index
#humans = Human.only([:name, :dob])
respond_to do |format|
format.json { render :json => #humans.to_json(:except => :_id) }
end
end
It works fine but I see this as a workaround rather than as the proper way to do what I want.
Ideally I would like to say something like #humans = Human.only([:name, :dob]).without(:_id) but this doesn't work as you can't combine only with without in mongoid. However, mongo allows you to use projections to exclude just the _id from a specific set of included attributes. Any ideas?
Take a look to https://github.com/nesquena/rabl
This helps you render lighter json responses. You can either create some keys and build there values with whatever you want without pollute your controller.
How about Human.pluck(:name, :dob)? It may not be exactly what you need though.
I am working on a migration project. Wanna migrate a rails 2.x app to 3.x. I have a problem with active record.
In Rails 2.x:
arr=StorageUnit.find(:all, :conditions =>"type='Drawer'")
The above code will get me all records with type Drawer.
arr.class
=> Array
In Rails 3.x:
Here the above function is deprecated. So i had to use
arr=StorageUnit.where("type='Drawer'")
The above code will get me all records with type Drawer.
arr.class
ActiveRecord::Relation
I guess this is because of the change in Active Record.
My problem is i have some code based on this class.
For ex:
if arr.class== Array
do something
else
do something
end
So as off now i have changed it to
if arr.class== ActiveRecord::Relation
do something
else
do something
end
Just curious to know whether there is any better solution or any alternative way to solve it. I have a lot of place where they have used such stuff.
EDIT:
arr=StorageUnit.where("type='Drawer'").all
will provide the class as Array. My objective is to know when the code without suffix can provide you the required records than what is the use of all in the end.? Is it just to change class? Can anyone ecxplain?
StorageUnit.where simply returns the ActiveRecord relation. Tacking on .all will execute the sql and create instances of StorageUnit.
arr = StorageUnit.where(:type => 'Drawer').all
There are many interesting side effects of it being returned as a relation. Amongst other things, you can combine scopes before executing:
StorageUnit.where(:type => 'Drawer').where(:color => 'black')
you can view the resultant sql for debugging:
StorageUnit.where(:type => 'Drawer').to_sql
Imagine this:
class StorageUnit < ActiveRecord::Base
scope :with_drawer, where(:type => 'Drawer')
scope :with_color, lambda { |c| where(:color => c) }
end
Now:
StorageUnit.with_drawer.with_color('black').first_or_create # return the first storage unit with a black drawer
StorageUnit.with_drawer.with_color('black').all # return all storage units with black drawers
The relation allows for underlying query to be built up even saved for later use. all and other modifiers like it have special meaning to the relation and trigger the database execution and building of model instances.
I have a rails app that has a list of Products, and therefore I have an index action on my ProductsController that allows me to see a list of them all.
I want to have another view of the products that presents them with a lot more information and in a different format -- what's The Rails Way for doing that?
I figure my main options are:
pass a parameter (products/index.html?other_view=true) and then have an if else block in ProductsController#index that renders a different view as required. That feels a bit messy.
pass a parameter (products/index.html?other_view=true) and then have an if else block in my view (index.html.haml) that renders different html as required. (I already know this is not the right choice.)
Implement a new action on my controller (e.g.: ProductsController#detailed_index) that has it's own view (detailed_index.html.haml). Is that no longer RESTful?
Is one of those preferable, or is there another option I haven't considered?
Thanks!
Another way of doing it would be via a custom format. This is commonly done to provide mobile specific versions of pages, but I don't see why the same idea couldn't be applied here.
Register :detailed as an alias of text/html and then have index.detailed.haml (or .erb) with the extra information. If you need to load extra data for the detailed view you can do so within the respond_to block.
Then visitors to /somecollection/index.detailed should see the detailed view. You can link to it with some_collection_path(:format=>'detailed')
I'm not sure whether this is 'bettrr' than the alternatives but there is a certain logic I think to saying that a detailed view is just an alternative representation of the data, which is what formats are for.
After doing some reading, I think that adding a new RESTful action (option #3 in my question) is the way to go. Details are here: http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
I've updated my routes.rb like this:
resources :products do
get 'detailed', :on => :collection
end
And added a corresponding action to my ProductsController:
def detailed
# full_details is a scope that eager-loads all the associations
respond_with Product.full_details
end
And then of course added a detailed.html.haml view that shows the products in a the detailed way I wanted. I can link to this with detailed_products_path which generates the URL /products/detailed.
After implementing this I'm sure this was the right way to go. As the RoR guides say, if I was doing a lot of custom actions it probably means I should have another controller, but just one extra action like this is easy to implement, is DRY and works well. It feels like The Rails Way. :-)
I'm getting strange output when using the following routing setup:
resources :warranty_types do
resources :decisions
end
resource :warranty_review, :only => [] do
resources :decisions
end
I have many warranty_types but only one warranty_review (thus the singular route declaration). The decisions are polymorphically associated with both. I have just a single decisions controller and a single _form.html.haml partial to render the form for a decision.
This is the view code:
= simple_form_for #decision, :url => [#decision_tree_owner, #decision.becomes(Decision)] do |form|
The warranty_type url looks like this (for a new decision):
/warranty_types/2/decisions
whereas the warranty_review url looks like this:
/admin/warranty_review/decisions.1
I think because the warranty_review id has no where to go, it's just getting appended to the end as an extension.
Can someone explain what's going on here and how I might be able to fix it?
I can work around it by trying to detect for a warranty_review class and substituting #decision_tree_owner with :warranty_review and this generates the correct url, but this is messy. I would have thought that the routing would be smart enough to realise that warranty_review is a singular resource and thus discard the id from the URL.
This is Rails 3 by the way :)
Apparently it's a long standing rails bug where polymorphic_url has no way of knowing whether a resource is singular or not from the routes setup:
https://rails.lighthouseapp.com/projects/8994/tickets/4077-wrong-redirect-after-creation-of-nested-singleton-resource-using-responder
I'm just going to resort to using a non-singular route even though there will only ever be one warranty_review. It's just aesthetics at the end of the day.