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
Related
I have this method:
method:
def unassigned_workers?(users)
assigned_users = []
unassigned_users = []
users.each do |user|
if user.designated_to_assignment?(self)
assigned_users << user
else
unassigned_users << user
end
end
if unassigned_users.count > 0
true
else
false
end
end
It's in my Assignment model. The assignment model has many Users, and basically what this method is trying to do is check if the user is designated to the assignment based on another relationship I have setup. It checks if the user is assigned and pushes it on the correct array. Does anybody know how I can refactor this to be smaller and more readable?
How about using any?
assigned_users not necessarily required.
def unassigned_workers?(users)
users.any? { |user| !user.designated_to_assignment?(self) }
end
not sure why you have assigned_users at all
try:
def unassigned_workers?(users)
users.reject { |user| user.designated_to_assignment?(self) }.count > 0
end
reject removes elements from a collection that match a predicate.
Moreover passing a self in a model as an argument is a code smell, maybe the dependencies are reversed
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
I have a record and I want to inset it inside and array and later access it.
users = User.all
results = []
users.each do |user|
results << {:name => user.name, :email => user.email}
end
is results variable still an array ? If yes how can I get all the names alongwith email?
Your example would create an array results filled with hashes containing each users name and email.
You could access it in several ways, the easiest of which is a simple loop:
results.each do |result|
name = result[:name]
email = result[:email]
end
You can also access individual items directly like so:
first_result_name = results[0][:name]
but be careful of trying to access results that may not be there.
Arrays
Hashes
But I have to ask, why do you want to do this? There's no gain from assigning all the Users name and emails to an array, User.all is no different really in functionality.
Yes, it's still an array. You can have what you want later for example with:
results.each do |result|
result[:name] # access to name
result[:email] # access to email
end
You just need one line to do it
results = users.collect{|user| {:name => user.name, :email => user.email}}
In a kind of unrelated way, your initial code could be rewritten as:
results = User.all.inject([]) do |array, user|
array << {:name => user.name, :email => user.email}
end
Given that "results" now contains this collection of hashes, if you want to print every user name and email you would do:
results.each do |user|
puts "#{user[:name]} #{user[:email]}"
end
Because of Ruby awesomeness it is possible to use any object as key
document = Document.find 1
o = Hash.new
o[1] = true
o[:coool] = 'it is'
o[document] = true
# an it works
o[document]
#=> true
but just because it is possible doesn't mean is good practice
However I have situation where in my controller I need to set something similar, so I can loop trough it in view
#controller
#users_with_things = Hash.new
Things.accessible_by(some_curent_user_logic).each do |thing|
#user_with_things[thing.user] ||= Array.new
#user_with_things[thing.user] << thing.id
end
#view
- #users_with_things.each do |user, thing_ids|
%input{type: :checkbox, name: "blank[user_#{user.id}]", value: 1, class: "select_groups", :'data-resource-ids' => "[#{thing_ids.join(',')}]", :'data-user-type' => user.type }
The reason why I want to do it this way is because I don't want to call from my view User.find_by_id (want to make it clean)
#controller
#users_with_things = Hash.new
Things.accessible_by(some_curent_user_logic).each do |thing|
#user_with_things[thing.user.id] ||= Array.new
#user_with_things[thing.user.id] << thing.id
end
#view
- #users_with_things.each do |user_id, thing_ids|
- user = User.find user_id
%input{type: :checkbox, name: "blank[user_#{user.id}]", value: 1, class: "select_groups", :'data-resource-ids' => "[#{thing_ids.join(',')}]", :'data-user-type' => user.type }
So my 1st question is: is it ok to use ActiveRecord object as Hash key in situation like this
I can imagine several scenarios where this may go wrong (sessions, when object changes in model and so on) however this is just for rendering in a view
Alternative !
so this is one way to do it, the other may be like this
#controller
#users_with_things = Hash.new
Things.accessible_by(some_curent_user_logic).each do |thing|
#user_with_things[thing.user.object_id] ||= Array.new
#user_with_things[thing.user.object_id] << thing.id
end
#view
- #users_with_things.each do |user_object_id, thing_ids|
- user = ObjectSpace._id2ref(user_object_id) #this will find user object from object_id
%input{type: :checkbox, name: "blank[user_#{user.id}]", value: 1, class: "select_groups", :'data-resource-ids' => "[#{thing_ids.join(',')}]"", :'data-user-type' => user.type }
...which is even more, hardcore. However it is way around if for some reason hash[ARobject] = :something would create big memory cluster for some reason
question 2 : is it good idea to do it this way ?
to be complete there is also another alternative and that is
# ...
#user_with_thing[ [thing.user.id, thing.user.type] ] << thing_id
# ...
so basically array object will be key
#user_with_thing[ [1, 'Admin'] ]
#=> [1,2,3]
I think to use a hash is a good way to organise in your situation. However, I would advise against using the user or to big an object as hash keys, simply because it renders your hash unreadable and because it is really only this sole object with it's object id that can be used as a key.
o = Object.new
h = { o => 'something' }
h[Object.new] #=> nil
In your situation, this may not be an issue, because you simply need to iterate it. But it may be a shot in the leg as soon as you want to do something else with that hash, or you have different instances of the same Active Record Data (which is very common in Rails applications, unless you are a really paying attention what gets loaded when). Besides that, I think it is good to stick by the widely used convention to use simple objects (strings, symbols) as hash keys to make your code readable and maintainable.
Maybe it would be best to keep a two-dimensional hash, like this:
#users_with_things = Things.accessible_by(some_curent_user_logic).inject({}) do |a, thing|
user_id = thing.user.id
a[user_id] ||= { :user => thing.user, :things => [] }
a[user_id][:thing] << thing
a
end
Then you can iterate over #users_with_things in your view like this:
#users_with_things.each do |user_id, values|
# values[:user] is the user, values[:things] the array of things
I have a query like so:
#users = User.where(:something => 'met')
This returns back #users with 1+ items
What I want to do is loop through the #user object to see if a condition is met, if the condition is met I want to delete the item from the object. I've been trying the following but it does not appear to work though does not error.
#users.each_with_index do |u, index|
#users.delete(index) if u.id == 12
end
Suggestions on a better way to make this work?
Thank you
Do you want to delete it from the database or just from the list?
In the former case, do
#users.each do |u|
u.delete if u.id == 12
end
In the latter, do
#users.reject! do |u|
u.id == 12
end
or, if the condition is some method on user returning "true"/"false"-ish values,
#users.reject! &:is_12
class User < ActiveRecord::Base
def is_12
self.id == 12
end
end
Array#delete_if :
#users.delete_if { |u| u.id == 12 }
You can also exclude it from the query all together:
User.where(:something => "met").where("id != ?", 12)
The reason your try isn't working is because Array#delete takes an object, not an index. So you'd have to tweak your example:
#users.each { |u| #users.delete(u) if u.id == 12 }
But that seems silly given the delete_if method :)
It's usually a better idea to exclude the record in question from your fetch:
#users = User.where(:something => 'met').where('id!=?', 12)
Otherwise you have to manipulate the result set. An easy way to do this is convert it to a Hash and delete the offending key(s):
#users = Hash[User.where(...).collect { |u| [ u.id, u ] }]
#users.delete(12)