Parsing array of multiple objects in Jbuilder - ruby-on-rails

How to extract values present in array of multiple object's using jbuilder.?
i have an array of multiple objects.
#array1= [ ]
#pushed different types of objects into this array.
if xyz
#array1 << object_type1 # having fields id,f_name
else
#array1 << object_type2 # having fields id,l_name
Now in jbuilder i want
json.array! #array1 do |myarray|
json.id myarray.id
json.name myarray.f_name || myarray.l_name # how to check object type here
end
when i try this it is giving me error like
undefined method `l_name' for #<Object_type1:0xb496eda8>
How to check or tell jbuilder to which objecttype it has to use for name field.?

If both of your ObjectTypes are ActiveRecord models, you can do something a bit cleaner like:
json.array! #array1 do |myarray|
json.name myarray.has_attribute? "f_name" ? myarray.f_name : myarray.l_name
json.id myarray.id
end
This checks if myarray has an attribute of f_name and if it does uses that, otherwise we know it's the other ObjectType so we use l_name. If you haven't seen a one line if/else statement like this before, the syntax I'm using is:
<condition> ? <if_true> : <if_false>
So you can do things like:
#post.nil? ? return "No post here" : return "Found a post"
Or you can add a method to each of your ObjectTypes in their models like:
def name
l_name # or f_name, depending on which ObjectType it is
end
Then you could do:
json.array! #array1 do |myarray|
json.name myarray.name
json.id myarray.id
end

i don't know whether it is a correct way or not but i tried and got what i wanted
json.array! #array1 do |myaarray|
if myarray.class == ObjectType
json.name myarray.f_name
json.id myarray.id
else
json.name myarray.l_name
json.id myarray.id
end
end

Related

Using jBuilder to build a complex array

I am using jBuilder and jsTree (https://www.jstree.com/docs/json/) in my Rails app and trying to build an array like this:
[
{
id : "string" // required
parent : "string" // required
text : "string" // node text
icon : "string" // string for custom
state : {
opened : boolean // is the node open
disabled : boolean // is the node disabled
selected : boolean // is the node selected
},
li_attr : {} // attributes for the generated LI node
a_attr : {} // attributes for the generated A node
},
{...},
{...}
]
I did this before with a simple json.array! and a do loop with a set of results from my database. No problems there. The issue is that I have polymorphic parents i.e. there are different models. I will equate this to an example where I have a 'Products' and 'Equipment' and they all have comments nested below. I want to list all the Projects (with child comments) then list all the Equipment and then child comments for them. I essentially need a loop like this:
[
projects do |p|
json.id id
json.parent "#"
...
end
equipment do |e|
json.id id
json.parent "#"
...
end
comments do |c|
json.id id
json.parent c.parent_id
...
end
]
This way I can build the hash of data for jsTree to parse. The docs for jBuilder are not great and not sure how or of I can do this.
I would just skip jBuilder. Its slow as heck and do you really need a super awkward DSL to build JSON objects? After all Rubys hashes and arrays map cleanly to JSON types.
class JsTreeSerializer
# #param [Array] records
# #param [Mixed] context - used to call view helpers
def initialize(records, context: nil)
#records = records
#context = context
end
def serialize
json = #records.map do |record|
{
id: record.id,
parent: record.parent_id,
icon: context.image_url('icon.gif')
# ...
}
end
end
end
Usage:
class MyController
def index
#records = get_all_the_types
respond_to do |f|
format.json do
render json: JsTreeSerializer.new(
#records,
context: view_context
).serialize
end
end
end
end
It ended up being as simple as:
json.array!
json.(#projects) do |p|
json.id id
json.parent "#"
...
end
json.(#equipment) do |e|
json.id id
json.parent "#"
...
end
json.(#comments) do |c|
json.id id
json.parent c.parent_id
...
end

ActiveRecord query alias field name output in jBuilder

Hi I am new to ruby on rails development. This is my controller function query
def index
#questions = Question.order('questions.created_at DESC').joins('left join favourites on questions.id=favourites.question_id and favourites.user_id='+current_user_id.to_s).includes(:user).select('CASE WHEN favourites.user_id='+current_user_id.to_s+' THEN 1 ELSE 0 END as favour').references(:favourite).page(params[:page]).per( (ENV['ILM_QUESTIONS_PER_PAGE'] || 15).to_i )
end
From this query i dont know how to get the value for "favour" column in select query.
This is my jbuilder file in views
/index.json.builder
json.number_of_items_per_page #questions.length
json.total_number_of_pages #questions.total_pages
json.user_favour #questions.favour
json.questions do
json.array! #questions do |question|
json.partial! 'api/v1/questions/question', question: question,include_comments: false
end
end
/_question.json.builder
json.id question.id
json.content question.content
json.created_at question.created_at
json.image_url question.image.url
when i put #questions.favour in index.json.builder
i got this error
undefined method `favour' for #<Question::ActiveRecord_Relation:0x0000000c39b5f0>
Please Advice me on this issue
Thanks in Advance.

How to completely remove an empty element from an array with JBuilder

When using JBuilder, how I can completely remove evidence of an empty array element from my output? For this code sample, assume that we have three users and the third user has a nil address:
json.array! #users.each do |user|
unless user.address.nil?
json.name user.name
json.address user.address
end
end
The resulting JSON is:
[
{
"name":"Rob",
"address":"123 Anywhere St."
},
{
"name":"Jack",
"address":"123 Anywhere St."
},
{}
]
See that last, empty {} at the end there. So any time the block passed to array! returns nil I end up with an empty element in the array, rather than a lack of element. Is there any easy way to tell JBuilder not to output those? Or do I just need to treat the output of array! as a plain ol' array and then compact or reject elements that I don't want?
I think you can avoid your use case by first using reject on the users, and only add the valid users to the array:
json.array! #users.reject { |user| user.address.nil? }.each do |user|
json.name user.name
json.address user.address
end
Maybe you can try select instead of each, it will return a value only for non-nil elements
json.array! #users.select do |user|
unless user.address.nil?
json.name user.name
json.address user.address
end
end

Conditionally chaining where clauses in Rails ActiveRecord queries

I have a form that when filled has to trigger a particular query, depending on which parameters the form has, so I have a method in my model that I believe should look like this:
def form_query(params)
query = ''
if params.has_key?('size')
query = query.where(size: params['size'])
end
if params.has_key?('title')
query = query.where(title: params['title'])
end
# More conditionals depending on params.
end
My question is, what does query have to be at the beginning? I put query = '', but I am wondering what has to be the base case, so I can conditionally add more 'where' clauses.
Queries aren't strings; they're query objects. So you want something like
query = YourModel.scoped # Rails 3; in Rails 4, use .all
if params.has_key?('size')
query = query.where(size: params['size'])
end
etc.
Alternatively, you can update your code as below:
def self.form_query(params)
options = {}
fields = ["body", "title"].freeze ## Add other options
if params.present?
fields.each do |field|
options[field] = params[field] if params[field]
end
end
if options.present?
where(options)
else
all ## or nil if you don't want to show any records in view
end
end
Also, form_query should be a class method in your model.
Add more options in the fields array that you would like to query against.
It not only makes your code compact but also makes a single database call.
Here is a more condensed version of Kirti Thorat's version:
FIELDS = ["size", "title"].freeze ## Add other options
def self.form_query(params)
return all unless params.present?
options = params.select { |k, _v| FIELDS.include? k.to_s }
options.present? ? where(options) : all
end
I have done k.to_s so you can pass params keys as either strings or symbols.
If you want to return nil if no params are passed you can do this:
FIELDS = ["size", "title"].freeze ## Add other options
def self.form_query(params)
return unless params.present?
options = params.select { |k, _v| FIELDS.include? k.to_s }
where(options) if options.present?
end

Rails 3: Search method returns all models instead of specified

What I'm trying to do: I have a model "Recipe" in which I defined a method "search" that takes an array of strings from checkboxes (I call them tags), and a single string. The idea is to search the db for recipes that has anything in it's 'name' or 'instructions' that contains the string, AND also has any of the tags matching it's 'tags' property.
Problem: The search method return all the recipes in my db, and doesn't seem to work at all at finding by the specific parameters.
The action method in the controller:
def index
#recipes = Recipe.search(params[:search], params[:tag])
if !#recipes
#recipes = Recipe.all
end
respond_to do |format|
format.html
format.json { render json: #recipe }
end
end
The search method in my model:
def self.search(search, tags)
conditions = ""
search.present? do
# Condition 1: recipe.name OR instruction same as search?
conditions = "name LIKE ? OR instructions LIKE ?, '%#{search[0].strip}%', '%#{search[0].strip}%'"
# Condition 2: if tags included, any matching?
if !tags.empty?
tags.each do |tag|
conditions += "'AND tags LIKE ?', '%#{tag}%'"
end
end
end
# Hämtar och returnerar alla recipes där codition 1 och/eller 2 stämmer.
Recipe.find(:all, :conditions => [conditions]) unless conditions.length < 1
end
Any ideas why it return all records?
if you are using rails 3, then it is easy to chain find conditions
def self.search(string, tags)
klass = scoped
if string.present?
klass = klass.where('name LIKE ? OR instructions LIKE ?', "%#{string}%", "%#{string}%")
end
if tags.present?
tags.each do |tag|
klass = klass.where('tags LIKE ?', "%#{tag}%")
end
end
klass
end
When you do
search.present? do
...
end
The contents of that block are ignored - it's perfectly legal to pass a block to a function that doesn't expect one, however the block won't get called unless the functions decides to. As a result, none of your condition building code is executed. You probably meant
if search.present?
...
end
As jvnill points out, it is in general much nicer (and safer) to manipulate scopes than to build up SQL fragments by hand

Resources