Rails to_json uses different DATE_FORMATS that .to_s - ruby-on-rails

With the following in my rails_defaults.rb:
Date::DATE_FORMATS[:default] = '%m/%d/%Y'
Time::DATE_FORMATS[:default]= '%m/%d/%Y %H:%M:%S'
Why do the following results differ:
ruby-1.9.2-p180 :005 > MyModel.find(2).to_json(:only => :start_date)
=> "{\"start_date\":\"2012-02-03\"}"
ruby-1.9.2-p180 :006 > MyModel.find(2).start_date.to_s
=> "02/03/2012"
And more importantly, how do I get to_json to use %m/%d/%Y?

Because the standard JSON format for a date is %Y-%m-%d and there's no way to change it unless you override Date#as_json (don't do so or your application will start misbehaving).
See https://github.com/rails/rails/blob/master/activesupport/lib/active_support/json/encoding.rb#L265-273
class Date
def as_json(options = nil) #:nodoc:
if ActiveSupport.use_standard_json_time_format
strftime("%Y-%m-%d")
else
strftime("%Y/%m/%d")
end
end
end

Related

conditions case not working correctly

i use acts-as-taggable-on for tagging.
apartments_controller
def index
if params[:tag]
#apartments = Apartment.tagged_with(params[:tag])
else
#apartments = Apartment.all
end
end
routes
resources :apartments do
#...
collection do
get ':tag', to: 'apartments#index', as: :tag
end
#...
I get nice urls by example /apartments/tag1 etc.
I want to show custom content based on the tag name in the apartments index template.
Apartment's index view:
- #appartments.each do |tags|
- case tags.tag_list
- when "tag1"
%p tag1 content
- when "tag2"
%p tag2 content
- else
%p default content
When i go to url apartments/tag1 the text "default content" is show and not "tag1 content".
What am I doing wrong?
There several notes about your code:
Keep your logic away from views. I.e. extract code into helper methods.
Do not use case on Enumerable, in your case it seems like an array. Use include? to check whether element is present inside an array:
1.9.3p194 :001 > a= [:a, :b, :c]
=> [:a, :b, :c]
1.9.3p194 :002 > case a
1.9.3p194 :003?> when :a
1.9.3p194 :004?> p '1'
1.9.3p194 :005?> when :b
1.9.3p194 :006?> p '2'
1.9.3p194 :007?> when :c
1.9.3p194 :008?> p '3'
1.9.3p194 :009?> when :d
1.9.3p194 :010?> p 'Never'
1.9.3p194 :011?> end
=> nil
1.9.3p194 :012 > a.include?(:c)
=> true

Rails render json with right timezone

I'm using rails app as iOS backend. There is small problem - how to render timestamps with user's timezone in json? I'm using default UTC timezone. How to converted it for example to +2? Maybe there is way how to override as_json method to convert timestamps before rendering?
Thanks for help!
You can convert the time to user's timezone before rendering json, then the timezone will be included.
1.9.3p125 :006 > t = Time.now.utc
=> 2012-10-20 13:49:12 UTC
1.9.3p125 :007 > {time: t}.to_json
=> "{\"time\":\"2012-10-20T13:49:12Z\"}"
1.9.3p125 :008 > t = Time.now.in_time_zone("Beijing")
=> Sat, 20 Oct 2012 21:49:19 CST +08:00
1.9.3p125 :009 > {time: t}.to_json
=> "{\"time\":\"2012-10-20T21:49:19+08:00\"}"
UPDATE: To convert the time into user's timezone for serialization, you can override this method read_attribute_for_serialization. See lib/active_model/serialization.rb of ActiveModel:
# Hook method defining how an attribute value should be retrieved for
# serialization. By default this is assumed to be an instance named after
# the attribute. Override this method in subclasses should you need to
# retrieve the value for a given attribute differently:
#
# class MyClass
# include ActiveModel::Validations
#
# def initialize(data = {})
# #data = data
# end
#
# def read_attribute_for_serialization(key)
# #data[key]
# end
# end
#
alias :read_attribute_for_serialization :send

Rails: Cannot Parse JSON object neither with hash key or index

Weird question tag but still wanted to ask because even though it looks easy no matter what I've tried I could not accomplish
I'm trying to parse duration between to points from a URL given by Google Maps directions API. Thanks an answer I've received from here I was able to capture the JSON object and get to the duration object however no matter what I did I could not get the inner values "text" or "value" from the "duration" attribute.
Here is the response;
{
"text" : "6 mins",
"value" : 373
}
And here is the code I've written in rails
#request = Net::HTTP.get(URI.parse('http://maps.googleapis.com/maps/api/directions/json?origin=40.983204,29.0216549&destination=40.99160908659266,29.02334690093994&sensor=false'))
hash = JSON.parse #request
duration = hash['routes'][0]['legs'][0]['duration']
respond_to do |format|
format.html {render :index}
format.json {render json: duration}
end
Note: Of course, the [0] and ['text'] methods have been tried.
As a first thing you need to define duration as an instance variable to have it available in your views (if this is where you need to use it)
#duration = hash['routes'][0]['legs'][0]['duration']
duration["text"] and duration["value"] didn't work?
1.9.3p194 :001 > require 'net/http'
=> true
1.9.3p194 :002 > require 'json'
=> true
1.9.3p194 :003 > #request = Net::HTTP.get(URI.parse('http://maps.googleapis.com/maps/api/directions/json?origin=40.983204,29.0216549&destination=40.99160908659266,29.02334690093994&sensor=false'));
1.9.3p194 :004 > hash = JSON.parse #request;
1.9.3p194 :005 > duration = hash['routes'][0]['legs'][0]['duration']
=> {"text"=>"6 mins", "value"=>373}
1.9.3p194 :006 > duration["text"]
=> "6 mins"
1.9.3p194 :007 > duration["value"]
=> 373

RESTful file uploads with CarrierWave

I'm trying to build an API backend for file uploads. I want to be able to upload files with a POST request that has a Base64-encoded string of the file. The server should decode the string, and save the file using CarrierWave. Here's what I have so far:
photo.rb:
class Photo
include Mongoid::Document
include Mongoid::Timestamps
mount_uploader :image_file, ImageUploader
end
image_uploader.rb:
class ImageUploader < CarrierWave::Uploader::Base
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
Rails console:
(summary)
ruby-1.8.7-p334 :001 > img = File.open("../image.png") {|i| i.read}
=> "\377���JFIF\000\001\002\001\000H\000H\000\000\377�Photoshop 3.0\0008BIM\003...
ruby-1.8.7-p334 :003 > encoded_img = Base64.encode64 img
=> 3af8A\nmLpplt5U8q+a7G2...
ruby-1.8.7-p334 :005 > p = Photo.new
=> #<Photo _id: 4e21b9a31d41c817b9000001, created_at: nil, updated_at: nil, _type: nil, user_id: nil, image_file_filename: nil>
ruby-1.8.7-p334 :006 > p.user_id = 1
=> 1
ruby-1.8.7-p334 :007 > p.image_file = Base64.decode64 encoded_img
\255��=\254\200�7u\226���\230�-zh�wT\253%����\036ʉs\232Is�M\215��˿6\247\256\177...
ruby-1.8.7-p334 :008 > p.save
=> true
ruby-1.8.7-p334 :009 > p.image_file.url
=> nil
full
The problem appears to be related to the process of converting a Base64-decoded string to a file. CarrierWave seems to expect a File object, and instead I'm giving it a String. So how do I convert that String to a File object. I'd like this conversion not to save anything to the file system, simply create the object and let CarrierWave do the rest.
CarrierWave also accepts a StringIO, but it expects a original_filename method, since it needs it for figuring out the file name and doing the extension check. How you do it changed between Rails 2 and 3, here's both methods:
Rails 2
io = StringIO.new(Base64.decode64(encoded_img))
io.original_filename = "foobar.png"
p.image_file = io
p.save
In Rails 3, you need to make a new class and then manually add original_filename back
class FilelessIO < StringIO
attr_accessor :original_filename
end
io = FilelessIO.new(Base64.decode64(encoded_img))
io.original_filename = "foobar.png"
p.image_file = io
p.save
You don't have to monkeypatch StringIO or put any of this in your model. You can override the cache!() method in your uploader definition. Or you can take it a step further and make a module for yourself to include. My file is a serialized string coming from a json document. The object passed in looks like this { :filename => 'something.jpg', :filedata => base64 string }.
Here is my module:
module CarrierWave
module Uploader
module BackboneLink
def cache!(new_file=sanitized_file)
#if new_file isn't what we expect just jump to super
if new_file.kind_of? Hash and new_file.has_key? :filedata
#this is from a browser, so it has all that 'data:..' junk to cut off.
content_type, encoding, string = new_file[:filedata].split(/[:;,]/)[1..3]
sanitized = CarrierWave::SanitizedFile.new(
:tempfile => StringIO.new(Base64.decode64(string)),
:filename => new_file[:filename],
:content_type => content_type
)
super sanitized
else
super
end
end
end
end
end
And then I can include it in an uploader.
uploaders/some_uploader.rb:
class SomeUploader < CarrierWave::Uploader::Base
include CarrierWave::Uploader::BackboneLink
class AppSpecificStringIO < StringIO
attr_accessor :filepath
def initialize(*args)
super(*args[1..-1])
#filepath = args[0]
end
def original_filename
File.basename(filepath)
end
end
also see the carrierwave wiki https://github.com/carrierwaveuploader/carrierwave/wiki/How-to%3A-Upload-from-a-string-in-Rails-3

Rails to_json Why are timestamps breaking, and being set to 2000-01-01T01:31:35Z

I'm building a json object in rails as follows:
#list = Array.new
#list << {
:created_at => item.created_at
}
end
#list.to_json
Problem is this gets received by the browser like so:
"created_at\":\"2000-01-01T01:31:35Z\"
Which is clearly not right, in the DB it has:
2011-06-17 01:31:35.057551
Why is this happening? Any way to make sure this gets to the browser correctly?
Thanks
You need to do some testing / debugging to see how that date is coming through.
For me, in Rails console (Rails 3.0.9, Ruby 1.9.2)
ruby-1.9.2-p180 :014 > d = Date.parse("2011-06-17 01:31:35.057551")
=> Fri, 17 Jun 2011
ruby-1.9.2-p180 :015 > #list = {:created_at => d}
=> {:created_at=>Fri, 17 Jun 2011}
ruby-1.9.2-p180 :016 > #list.to_json
=> "{\"created_at\":\"2011-06-17\"}"
i.e. it's just fine. Can you see whether the date is really ok?
The trouble lies with the way to_json escapes characters. There is a very good post on the subject here:
Rails to_json or as_json
You may need to look into overriding as_json.

Resources