Rails easyist way to create hash with certain attributes and also nested - ruby-on-rails

In my controller I have:
def search
#sog = Konkurrencer.where("titel like ?", "%#{params[:q]}%")
#kate = []
#sog.each do |kat|
h = {}
kat.attributes.each{|k,v| h[k] = v.respond_to?(:force_encoding) ? v.dup.force_encoding("UTF-8") : v }
#kate << h
end
respond_to do |format|
format.html
format.json { render :json => #kate }
end
The problem is that the JSON contains all the attributes for the model. How do I create a JSON that have only ID, url and titel?
The JSON should also contain the key "url" which key should be the URL for the associated photo. I use paperclip. The path is: #konkurrencer.photo.image.url
UPDATE:
My search.json.erb:
[
<% #sog.each do |kon| %>
{"id":"<%= kon.id %>","titel":"<%= kon.titel %>"},
<% end %>
]
How do I remove the , for the last loop?

Create an array with the list of attributes you want to display. Use select query method to get only this fields in the SQL request. And finally loop on this attributes to fill the JSON array:
def search
displayed_attributes = %w{id url titel}
#sog = Konkurrencer.select(displayed_attributes.join(',')).where("titel like ?", "%#{params[:q]}%")
#kate = []
#sog.each do |kat|
h = {}
displayed_attributes.each do |attribute|
v = kat[attribute]
h[attribute] = v.respond_to?(:force_encoding) ? v.dup.force_encoding("UTF-8") : v
end
#kate << h
end
respond_to do |format|
format.html
format.json { render :json => #kate }
end
end

Related

Ruby on Rails filter array using three fields

I am trying to search through my model using 3 columns. Also if the column is empty, it is valid. This is how I am doing it
def getactivityfortoday
#temp = params[:temp]
logger.debug "params temp:#{#temp.inspect}"
#sky = params[:sky]
#day = params[:day]
#todaysactivities = []
#activities=[]
#finaldata = []
#activities = Weatherclockactivity.all
#attemptactivities = []
#attemptactivities = #user.attempts
for activity in #activities do
logger.debug "activity: #{activity.attributes.inspect}"
if #temp.to_i < activity.temperatureMax.to_i && #temp.to_i > activity.temperatuureMin.to_i
if #sky == activity.sky || activity.sky == ""
if #day == activity.day
#todaysactivities << activity
end
end
end
end
for activity in #todaysactivities
for attempt in #attemptactivities
if attempt == activity
finaldata << {activity: activity, attempt: "yes"}
else
finaldata << {activity: activity, attempt: "no"}
end
end
end
respond_to do |format|
format.html { render action: "new" }
format.json { render json: #finaldata }
end
The response I get is an empty array but I should be getting 3 rows as a response.
spelling mistake here
activity.temperatuureMin.to_i
And
finaldata << {activity: activity, attempt: "yes"}
should be
#finaldata << {activity: activity, attempt: "yes"}
Also you could be more concise
def getactivityfortoday
#temp = params[:temp]
logger.debug "params temp:#{#temp.inspect}"
#sky = params[:sky]
#day = params[:day]
#activities = Weatherclockactivity.all
#attemptactivities = #user.attempts
#finaldata = #activities.map do |activity|
if (activity.temperatureMin.to_i + 1...activity.temperatureMax.to_i).include?(#temp.to_i) && ( #sky == activity.sky || activity.sky == "") && #day
#attemptactivities.include?(activity) ? {activity: activity, attempt: "yes"} : {activity: activity, attempt: "no"}
end
end.compact
respond_to do |format|
format.html { render action: "new" }
format.json { render json: #finaldata }
end
end
How about something like this?
I tried to make it a balance of readability and conciseness. First we filter for the desired activities. Then we structure the output. This should be easier to debug.
def getactivityfortoday
#temp = params[:temp].to_i
#sky = params[:sky]
#day = params[:day]
#activities = Weatherclockactivity.all
#attemptactivities = #user.attempts
selected_activities = #activities.select do |activity|
# Make sure it's the right temperaure
return false unless (activity.temperatureMin.to_i + 1 ... activity.temperatureMax.to_i).include? #temp
# Make sure the sky matches, or the sky is blank
return false unless (#sky.blank? || #sky.activity == activity.sky)
# Make sure the day matches
return false unless #day == activity.day
# Otherwise, it's good!
return true
end
selected_attempted_activities = selected_activities.map do|activity|
ret = {activity: activity}
ret[:attempt] = #attemptactivities.include?(activity) ? "yes" : "no"
ret
end
respond_to do |format|
format.html { render action: "new" }
format.json { render json: selected_attempted_activities }
end
end
There are a few typos in your original (for instance, #finaldata not finaldata). Make sure that you spell instance variables (things starting with #, like #sky) correctly, since if you try to access an undefined instance variable, it'll silently default to nil.
The best and flexible way is to use ActiveModel::Model
It allows you to use many more useful methods.
it will seems like:
app/models/activity_report.rb
Class ActivityReport
include ActiveModel::Model
attr_accessor :day, :activity # and etc.
validates :day, presence: true
def day
#day.to_s # for example
end
def day=(value)
#day = value - 1.month # for example every date which user set will set on one month ago
end
# and etc
end
app/controllers/posts_controller.rb
...
def index
#activity = ActivityReport.new(params[:activity])
end
def create
#activity.create!
end
...
app/views/posts/index.html.haml
= form_for #activity do |f|
= f.day
For more information you could take a look at:
http://edgeapi.rubyonrails.org/classes/ActiveModel/Model.html
http://railscasts.com/episodes/219-active-model (old)
http://railscasts.com/episodes/416-form-objects (newer, but a little complex)

Rails json response. Int converting to date

I have a problem, with responding data in json.
Here is a code:
#data [
actions_by_type.each do |action|
[ action[:date].to_i, action[:activity] ]
end
]
respond_to do |format|
format.json { render :json => #data }
end
But responde is:
...{"date":"2013-04-29T20:20:00Z","activity":"87"}...
Why rails convert my int time, to string datetime?
You should use .map instead of .each.
#data = actions_by_type.map do |action|
[ action[:date].to_i, action[:activity] ]
end
respond_to do |format|
format.json { render :json => #data }
end
With .each the result of #data will be the actions_by_type instead of the new array.
x.each returns x so this:
x = actions_by_type.each do |action|
[ action[:date].to_i, action[:activity] ]
end
is equivalent to:
x = actions_by_type
You want to use map instead of each:
#data = actions_by_type.map do |action|
[ action[:date].to_i, action[:activity] ]
end

How to get the whole array of name in one array object using json?

In my code,i am parsing a JSON object like
[{"name":"karthi"},{"name":"shreshtt"},{"name":"jitu"},{"name":null},{"name":null},{"name":null},{"name":null}]
In this, I want to collect all names in an single array object. This is how my controller looks as of now. I want to store the resultant name array in #hotels variable.
controller.erb
respond_to :json, :xml
def index
#hotels = Hotel.all
respond_to do |format|
format.html # show.html.erb
format.json { render json: #hotels.to_json(:only => [ :name ]) }
end
end
view/hoels/index.json.erb
[
hotel: <% #hotels.each do |hotel| %>
{ 'name': "<%= hotel.name.to_json.html_safe %>" }
<% unless index== #hotels.count - 1%>
<% end %>
<% end %>
]
You want to add just the names to an array?
How about:
a = [{name: "karthi"},{name: "shreshtt"},{name: "jitu"},{name: nil},{name: nil},{name: nil},{name: nil}]
#hotel = []
a.collect{|a_name| #hotel << a_name[:name]}
=> ["karthi", "shreshtt", "jitu", nil, nil, nil, nil]
#hotel.compact!
=> ["karthi", "shreshtt", "jitu"]
What´s about that?
a = {}
a["hotel"] = []
array = [{"name"=>"kathi"}, {"name"=>"kathi2"}, {"name"=>"kathi3"}, {"name"=>"kathi4"}, {"name" => nil}]
a["hotel"] = array
a["hotel"].each do |v|
if v["name"] == nil
a["hotel"].delete(v)
end
end
a => {"hotel"=>[{:name=>"kathi"}, {:name=>"kathi2"}, {:name=>"kathi3"}, {:name=>"kathi4"}]}
You can do like following
hotels = Hotel.select("name").where("name is not NULL")
json_obj = {hotels: hotels}.to_json
format.json { render json: json_obj }

Map field value in ruby

I have such class-array:
#types = Type.where("TYP_MOD_ID = ?", params[:mod_id])
There are i have field TYP_KV_FUEL_DES_ID which is number....
But how can i via map method change this value via method?
I have tried something like:
def get_types_for_mod2
#types = Type.where("TYP_MOD_ID = ?", params[:mod_id])
#types.map { |e| e.TYP_KV_FUEL_DES_ID = get_via_designation(e.TYP_KV_FUEL_DES_ID) }
respond_to do |format|
format.json { render :json => #types}
end
end
def get_via_designation(id)
designation = Designation.find_by_DES_ID(id)
destext = DesText.find_by_TEX_ID(designation.DES_TEX_ID)
destext.TEX_TEXT
end
So how can i change value of e.TYP_KV_FUEL_DES_ID ?
upd1:
i don't need to commit anything! just for json i fetch data and change for view some field! no db!
#types = Type.where("TYP_MOD_ID = ?", params[:mod_id]).map do |type|
type.TYP_KV_FUEL_DES_ID = get_via_designation(type.TYP_KV_FUEL_DES_ID)
type
end
here we will map over the result from the query Type.where("TYP_MOD_ID = ?", params[:mod_id]) and set the TYP_KV_FUEL_DES_ID to the return from get_via_designation
UPDATE: added that the map block will return "type"

Trying to push results of hash to an array - Ruby on rails

I'm just beginning to (hopefully!) learn programming / ruby on rails and trying to push the results of a hash to an array using:
ApplicationController:
def css_class
css = Array.new
product = {#product.oil => ' oil', #product.pressure_meters => ' pressure_meters', #product.commercial => 'commercial'}
product.each do |key, value|
if key == true
css.push(value)
end
end
сss.join
end
And this in the ProductsController:
def create
#product = Product.new(params[:product])
#product.css_class = css_class
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render json: #product, status: :created, location: #product }
else
format.html { render action: "new" }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
This only seems to only save the last thing that was pushed to the array, I tried the below code on it's own and it seems to work, so I'm baffled as to where I'm going wrong?
def css_class
css = Array.new
product = {1 => ' pressure_meters', 2 => ' oil'}
product.each do |key, value|
if key > 0
css.push(value)
end
end
css.join
end
puts css_class
Thanks in advance.
In Ruby Hash can't have duplicate keys so
def css_class
css = Array.new
product = { #product.oil => ' oil',
#product.pressure_meters => ' pressure_meters',
#product.commercial => 'commercial' }
product.each do |key, value|
if key == true
css.push(value)
end
end
сss.join
end
will not work because
irb(main):0> h = { true => 'foo', true => 'bar', false=>'foo', false => 'bar' }
=> {true=>"bar", false=>"bar"}
your second example works only because you have distinct keys (1,2) so let's refactor your code a bit
def css_class
css = ""
product = { ' oil' => #product.oil,
' pressure_meters' => #product.pressure_meters,
' commercial' => #product.commercial }
product.each do |key, value|
css << key if value
end
сss.strip
end
it can be simplified even more however previous version should work fine too
def css_class
[ "oil ", "pressure_meters ", "commercial " ].inject(""){ |sum, val| sum += val if #product.send( val.strip ) }.strip
end
You can use Hash#values to get an array of your hash's values.
So:
product_values = product.values
And conditionally, you could pick the ones you want using select, like this:
product_values = product.select {|k,v| k == true }.values
Which is verbose for:
product_values = product.select {|k,v| k }.values
Thanks for pointing me in the right direction. I kept getting a 500 internal server error with your code Bohdan, not sure why, but played around with it and eventually found this to work:
def css_class
css = Array.new
product = { ' oil' => #product.oil,
' pressure_meters' => #product.pressure_meters,
' commercial' => #product.commercial }
product.each do |key, value|
css << key if value
end
css.join
end

Resources