how can i get the values using include with conditions in rails? - ruby-on-rails

I have the shop with has_many association and include items to it so that the items belonging to that shop is received
format.json { render json: {:shop => #shops.as_json(:include => :items)}}
now it gives all the items that belongs to that shop but i want to get items with specific condition, say item_type = "accessories". so how can i do this? please help me.
EDIT
I have put a new question in How to get the value of include with conditions?

You should filter the data with ActiveRecord, and then call the as_json on the filtered data.
You can do something like:
#shops = Shop.includes(:items).where("items.itemp_type = ?", 'accesories')
format.json { render json: { :shop => #shops.as_json(:include => :items) } }

One way you could do this is to create a hash with the objects you want to render, and then pass that to the render method. Like so:
respond_to do |format|
format.json { render :json => {:shops => #shops,
:items => #items }}
end
If the models aren't associated through active record, that's probably your best solution.
If an association does exist, you can pass an :include argument to the render call, like so:
respond_to do |format|
format.json { render :json => #shops.to_json(:include => [:items])}
end
Note that you wouldn't have to retrieve the #items variable in the section above if you take this approach, Rails will automatically load it from the #shops variable.

Related

Filtering nested model collections in to_json include in Rails

To start out I have already looked at this thread and this thread.
I have a piece of code that has a couple different postgres calls, and then appends on another model collection named Category within our response. I want to filter out certain pieces of response depending on a search param passed in by the json. My current code is here:
def clues
....
clues = clues.where("category_id = ?", params[:category]) if params[:category].present?
offset = params[:offset].present? ? params[:offset] : 0
#result = clues.limit(100).offset(offset)
respond_to do |format|
if(!params[:category_keyword])
format.json { render :json => #result.to_json(:include => :category) }
else
format.json { render :json => #result.to_json(:include => Category.where("title LIKE ?", '%' + params[:category_keyword] + '%')) }
end
end
end
Right now, the end if statement in the respond_to do is broken, as I don't think my :include for the else statement is in a correct format to filter out, as it just doesn't append the nested model to my json response. What is the best way to filter out these nested calls?

How to get the value of include with conditions?

I have three table say shop, item and item_type
the shop contains names of shops and item contains items of each shop and item_type contains different types of that items along with the status such as available or not available.
Now i want to render
format.json { render json: {:shop => #shops.as_json(:include => :items)}}
but based on the condition, say items with the item_type_id='1' and status of the item_type_status='available'
Try this:
#shops = Shop.includes(:items).where("items.itemp_type = ?", 'accesories')
format.json { render json: { :shop => #shops.as_json(:include => :items) } }
Edited:
One way you could do this is to create a hash with the objects you want to render, and then pass that to the render method. Like so:
respond_to do |format|
format.json { render :json => {:shops => #shops,
:items => #items }}
end
If the models aren't associated through active record, that's probably your best solution.
If an association does exist, you can pass an :include argument to the render call, like so:
respond_to do |format|
format.json { render :json => #shops.to_json(:include => [:items])}
end
Note that you wouldn't have to retrieve the #items variable in the section above if you take this approach, Rails will automatically load it from the #shops variable.
You can pass method or methods to to_json or as_json methods and include needed records. Example from Rails api:
user.as_json(:methods => :permalink)
# => {"id": 1, "name": "Konata Izumi", "age": 16,
"created_at": "2006/08/01", "awesome": true,
"permalink": "1-konata-izumi"}

Rails Include filtered model in Json object

I have the following controller code
respond_with(#employees) do |format|
format.json { render :json => #employees.to_json(:include => :shifts) }
end
What do i have to do if i want to filter the shifts which are included? For example by a date.
I have to be able to set the filter parameters in the controller.
Edit:
I thought about using :method but it creates another variable in the json object. It has to be called "shifts"
format.json { render :json => #employees.includes(:shifts).where("shifts.date > ?", your_date_here).to_json(:include => :shifts) }

Model types and sorting in Rails?

This is something I've been stuck on for a while now, and I have to apologize in advance for going into so much detail for such a simple problem. I just want to make it clear what I'm trying to do here.
Scenario
So, there's a model Foo, each Foo can either be red, green, or blue. Having URLs like /reds to list all red objects, and /reds/some-red-object to show a certain object. In that "show" view, there should be next/previous links, that would essentially "find the next RedFoo in alphabetical order, and once at the last RedFoo, the next record should be the first GreenFoo, continuing in alphabetical order, and so on".
I've tried implementing this in a couple of ways and mostly ended up at a roadblock somewhere. I did get it working for the most part with single table inheritance though, having something like this:
class Foo < ActiveRecord::Base
class RedFoo < Foo
class GreenFoo < Foo
class BlueFoo < Foo
Each subclass's models and controllers are identical, just replace the model names. So the controllers look something like:
class RedFoosController < ApplicationController
def index
#foos = RedFoo.find(:all, :order => "title ASC")
respond_to do |format|
format.html { render :template => 'foos/index'}
format.xml { render :xml => #foos }
end
end
def show
#foo = RedFoo.find(params[:id])
respond_to do |format|
format.html { render :template => 'foos/show'}
format.xml { render :xml => #foo }
end
end
def new
#foo = RedFoo.new
respond_to do |format|
format.html { render :template => 'foos/new'}
format.xml { render :xml => #foo }
end
end
def edit
#foo = RedFoo.find(params[:id])
respond_to do |format|
format.html { render :template => 'foos/edit'}
end
end
def create
#foo = RedFoo.new(params[:foo])
respond_to do |format|
if #foo.save
flash[:notice] = 'Foo was successfully created.'
format.html { redirect_to(#foo) }
format.xml { render :xml => #foo, :status => :created, :location => #foo }
else
format.html { render :action => "new" }
format.xml { render :xml => #foo.errors, :status => :unprocessable_entity }
end
end
end
def update
#foo = RedFoo.find(params[:id])
respond_to do |format|
if #foo.update_attributes(params[:foo])
flash[:notice] = 'Foo was successfully updated.'
format.html { redirect_to(#foo) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #foo.errors, :status => :unprocessable_entity }
end
end
end
def destroy
#foo = RedFoo.find(params[:id])
#foo.destroy
respond_to do |format|
format.html { redirect_to(foos_url) }
format.xml { head :ok }
end
end
end
The models only contain methods for next/previous, which work fine, surprisingly.
class RedFoo < Foo
def next
if self == RedFoo.find(:all, :order => "title ASC").last
GreenFoo.find(:all, :order => "title ASC").first
else
RedFoo.find(:first, :conditions => ["title > ?", self.title], :order => "title ASC")
end
end
def previous
if self == RedFoo.find(:all, :order => "title ASC").first
BlueFoo.find(:all, :order => "title ASC").last
else
RedFoo.find(:first, :conditions => ["title < ?", self.title], :order => "title DESC")
end
end
end
Problem
For whatever reason when I try to create and edit records, none of the attributes get saved in the database. It simply adds a new record with completely empty columns, regardless of what's filled in the form. No errors get returned in the script/server output or in the log files. From the script/console however, everything works perfectly fine. I can create new records and update their attributes no problem.
It's also quite a bad code smell that I have a lot of code duplication in my controllers/models (they're using the same views as the base model, so that's fine though). But I think that's unavoidable here unless I use some meta-goodness.
Any advice or suggestions about tackling this record saving issue would be great, but the reason I posted my setup in detail is because I have a feeling I'm probably going about this whole thing the wrong way. So, I'm open to other approaches if you know of something more practical than using STI. Thanks.
Update
The parameters hash looks about right:
{"commit"=>"Create", "authenticity_token"=>"+aOA6bBSrZP2B6jsDMnKTU+DIAIkhc8fqoSicVxRJls=", "red_foo"=>{"title"=>"Hello world!"}}
But #foo.inspect returns the following RedFoo object (all nil, except for type):
#<RedFoo id: nil, title: nil, type: "RedFoo", created_at: nil, updated_at: nil>
Problem is the params
:red_foo
is the name of the params in the view, whereas you use
params[:foo]
in the controller, I think the best way would be to be use :foo, in the view by using text_field_tag rather than any (what i assume can be) form builders text_field.
You can get out of the controller smell by using a module to do the basic crud stuff, since i assume most of the new/create/edit/update/destroy stuff is the same
OR
you could map all the routes to a foo controller and use some sort of parameter either passed in from the route, or through URI analysis to get the red/green/blue foo
Please take a look at the section called "Single table inheritance" on this page and let us know if it solves your problem.
Must admit, the way I go about STI is to use set_table_name inside a model.
e.g.
class RedFoo < AR::Base
set_table_name "foos"
include FooModule
extend FooClassModule # for self methods
def next; ...; end
end
But anyway, for this situation, what does your logger say when you do a #foo.inspect just before a save, and also what is the SQL that is ran on insert/update?
Right, so #foo.inspect gives you "nil" in the log?
What I mean (if I wasn't clear enough) was:
def create
#foo = RedFoo.new(params[:foo])
logger.error "******************* foo: #{#foo.inspect} **************"
respond_to do |format|
if #foo.save
...
if you do that and tail -f your log you can easily find out what is happening to foo and compare that to the incoming params hash
Infact, that would also be some useful information to have, what is the params hash?

Validating data of a model from another controller in Rails

I have two tables:
Client(id,name,...)
Purchase(id,item,date,client_id,...)
They have their respective Model, with their validations. What I need is to create a new client with a new purchase, all into the create method of Client controller. Something like this:
def create
#client = Client.new(params[:client])
respond_to do |format|
if #client.save
# Add purchase
#sell = Purchase.new
#sell.client_id = #client.id
#sell.date = params[:date]
# Fill another fields
if #sell.save
# Do another stuff...
else
format.html { render :action => "new" }
format.xml { render :xml => #client.errors, :status => :unprocessable_entity }
end
flash[:notice] = 'You have a new client!'
format.html { redirect_to(:action => :show, :id => #evento.id) }
format.xml { render :xml => #client, :status => :created, :location => #client }
else
format.html { render :action => "new" }
format.xml { render :xml => #evento.client, :status => :unprocessable_entity }
end
end
end
In Purchase's model I have:
belongs_to :client
validates_format_of :date, :with => /^20[0-9]{2}[-][0-9]{2}[-][0-9]{2}$/, :message => 'not valid'
validates_presence_of :date
And there is my problem: how can I validate the date input, through validations into the model, from Client controller? And, how can I rollback the new client created when errors?
Yes, I can do the check as the very first instruction in the method, with a regular expression, but I think it's ugly. I feel like might exist a conventional method for doing this validation or even doing all the stuff in another way (i.e. calling create method for Purchase from Client controller).
Can you put me back in the right way?
Thank you in advance.
Take a look at the following page on working with associations.
Rails provides you with a bunch of handy methods on your objects.
Like the following:
Client.purchases.empty?
Client.purchases.size,
Client.purchases
Client.purchases<<(purchase)
Client.purchases.delete(purchase)
Client.purchases.find(purchases_id)
Client.purchases.find_all(conditions)
Client.purchases.build
Client.purchases.create
When using these methods, you're taking advantage of the validations on each of the models.
Hop into your Rails console and create a new client and try any of the above methods. You'll quickly learn how powerful they are and you'll be on your way in no time.
Edit: Here's a much better guide on Rails associations!
Depends a little on the situation, but you can use validates_associated to run the validations on associated objects. Then you can create the user (but don't save), create the purchase (but don't save) and try to save the user. If you've done it right the user will fail to save with a validation error on the associated object.

Resources