Identical hashes returned from lambda behaving differently - ruby

I'm using Paperclip for uploads to a Rails 4 image server. We want to track different image sizes and be able to generate new sizes on the fly if an existing style with the requested size does not exist.
To do this we have, in addition to a Photo model, a Size model belonging to Photo. I'm using a lambda to generate a hash object from photo.instance.sizes and pass that into Paperclip's :styles parameter. The hash gets generated just fine and when I log it to standard output I see a hash with the default size in Paperclip's desired format. {:medium=>"300x300#"} (worth noting the keys in the generated hash are symbolic, Paperclip doesn't like string keys)
When this hash is being returned from the lambda, no additional styles are generated and only the original resolution is saved. However, when I return a hard-coded hash (default var in code below) with the same contents, the additional style "medium" is generated (along with the original).
I made sure the hard coded hash was exactly the same as the one generated from photo.instance.sizes by logging an === comparison which returns true.
Here's the has_attached_file from the Photo model:
has_attached_file :asset,
:styles => lambda { |photo|
# Empty hash will contain paperclip formatted style options
styles = {}
# Get instance of model and iterate over its sizes
photo.instance.sizes.each do |size|
# Paperclip style format { :style_name => "WIDTHxHEIGHT#" } trailing pound means crop and retain aspect ratio
styles[size.name.to_sym] = "#{size.width}x#{size.height}#"
end
# default = { medium: "300x300#" }
styles
},
:storage => :s3,
:path => "/assets/:idhash/:style.:extension",
:s3_credentials => {:bucket => ENV["AWS_BUCKET"], :access_key_id => ENV["AWS_ACCESS_KEY_ID"], :secret_access_key => ENV["AWS_ACCESS_KEY_SECRET"]}
Any insight (or an alternative) would be greatly appreciated!

Related

build a hash from iterating over a hash with nested arrays

I'd like to structure data I get pack from an Instagram API call:
{"attribution"=>nil,
"tags"=>["loudmouth"],
"location"=>{"latitude"=>40.7181015, "name"=>"Fontanas Bar", "longitude"=>-73.9922791, "id"=>31443955},
"comments"=>{"count"=>0, "data"=>[]},
"filter"=>"Normal",
"created_time"=>"1444181565",
"link"=>"https://instagram.com/p/8hJ-UwIDyC/",
"likes"=>{"count"=>0, "data"=>[]},
"images"=>
{"low_resolution"=>{"url"=>"https://scontent.cdninstagram.com/hphotos-xaf1/t51.2885-15/s320x320/e35/12145134_169501263391761_636095824_n.jpg", "width"=>320, "height"=>320},
"thumbnail"=>
{"url"=>"https://scontent.cdninstagram.com/hphotos-xfa1/t51.2885-15/s150x150/e35/c135.0.810.810/12093266_813307028768465_178038954_n.jpg", "width"=>150, "height"=>150},
"standard_resolution"=>
{"url"=>"https://scontent.cdninstagram.com/hphotos-xaf1/t51.2885-15/s640x640/sh0.08/e35/12145134_169501263391761_636095824_n.jpg", "width"=>640, "height"=>640}},
"users_in_photo"=>
[{"position"=>{"y"=>0.636888889, "x"=>0.398666667},
"user"=>
{"username"=>"ambersmelson",
"profile_picture"=>"http://photos-h.ak.instagram.com/hphotos-ak-xfa1/t51.2885-19/11909108_1492226137759631_1159527917_a.jpg",
"id"=>"194780705",
"full_name"=>""}}],
"caption"=>
{"created_time"=>"1444181565",
"text"=>"the INCOMPARABLE Amber Nelson closing us out! #loudmouth",
"from"=>
{"username"=>"alex3nglish",
"profile_picture"=>"http://photos-f.ak.instagram.com/hphotos-ak-xaf1/t51.2885-19/s150x150/11906214_483262888501413_294704768_a.jpg",
"id"=>"30822062",
"full_name"=>"Alex English"}}
I'd like to structure it in this way:
hash ={}
hash {"item1"=>
:location => {"latitude"=>40.7181015, "name"=>"Fontanas Bar", "longitude"=>-73.9922791, "id"=>31443955},
:created_time => "1444181565",
:images =>https://scontent.cdninstagram.com/hphotos-xaf1/t51.2885-15/s320x320/e35/12145134_169501263391761_636095824_n.jpg"
:user =>"Alex English"}
I'm iterating over 20 objects, each with their location, images, etc... how can I get a hash structure like the one above ?
This is what I've tried:
array_images = Array.new
# iterate through response object to extract what is needed
response.each do |item|
array_images << { :image => item.images.low_resolution.url,
:location => item.location,:created_time => Time.at(item.created_time.to_i), :user => item.user.full_name}
end
Which works fine. So what is the better way, the fastest one?
The hash that you gave is one item in the array stored at the key "data" in a larger hash right? At least that's how it is for the tags/ endpoint so I'll assume it's the same here. (I'm referring to that array of hashes as data)
hash = {}
data.each_with_index do |h, idx|
hash["item#{idx + 1}"] = {
location: h["location"], #This grabs the entire hash at "location" because you are wanting all of that data
created_time: h["created_time"],
image: h["images"]["low_resolution"]["url"], # You can replace this with whichever resolution.
caption: h["caption"]["from"]["full_name"]
}
end
I feel like you want a more simple solution, but I'm not sure how that's going to happen as you want things nested at different levels and you are pulling things from diverse levels of nesting.

Ruby find key by name inside converted JSON array of hashes

I have a Ruby hash converted from JSON data, it looks like this:
{ :query => {
:pages => {
:"743958" => {
:pageid => 743958,
:ns => 0,
:title => "Asterix the Gaul",
:revisions => [ {
:contentformat => "text/x-wiki",
:contentmodel => "wikitext",
:* => "{{Cleanup|date=April 2010}}\n{{Infobox graphic novel\n<!--Wikipedia:WikiProject Comics-->...
All the good stuff is inside the revisions array and then the Infobox hash.
The problem I have is getting to the Infobox hash. I can't seem to get to it. The pages and pageid hashes might not exist for other entries and of course the ID would be different.
I've tried all sorts of methods I could think of like .map, .select, .find, .include?, etc to no avail because they are not recursive and will not go into each key and array.
And all the answers I've seen in StackOverflow are to get the value by name inside a one-dimensional array which doesn't help.
How can I get the Infobox data from this?
Is this what you're looking for?
pp data
=> {:query=> {:pages=>
{:"743958"=>
{:pageid=>743958,
:ns=>0,
:title=>"Asterix the Gaul",
:revisions=>
[{:contentformat=>"text/x-wiki",
:contentmodel=>"wikitext",
:*=>"{{Cleanup..."}]}}}}
# just return data from the first revisionb
data[:query][:pages].map{|page_id,page_hash| page_hash[:revisions].first[:"*"]}
=> ["{{Cleanup..."]
# get data from all revisions
data[:query][:pages].map{|page_id,page_hash| page_hash[:revisions].map{|revision| revision[:"*"] }}.flatten
=> ["{{Cleanup..."]

Create 3 color conditional formatting with axlsx

With axlsx, the following
color_scale = Axlsx::ColorScale.new do |c_s|
c_s.colors[1].rgb = "FFFFFF00"
end
color_scale.add :type => :percentile, :val => 50, :color => "FF00FF00"
worksheet.add_conditional_formatting("B3:B100", { :type => :colorScale, :operator => :greaterThan, :formula => "100000", :priority => 1, :color_scale => color_scale })
creates a basic 3 color conditional formatting, but the colors are pretty garish, making it hard to distinguish between slightly smaller and slightly larger values.
Is it necessary to reverse-engineer the colors Excel uses in order to create something that looks like the default 3 color conditional formatting that Excel provides?
For color scales, Excel will by default prefer Themes, while Axlsx is currently expecting you to specify exactly what you want. This is partly for interoperability but mostly because I have not ran into a use case that requires similarity to Excel's defaults.
That said, Axlsx should do what it can to give you some sensible defaults and I am sure you can understand how your request is an excellent opportunity to improve this area.
Would you be so kind as to send me a sample xlsx of what you are trying to achieve?
I am sure that I can add a bit of sugar in to make you a bit happier with the results you are seeing now and hopefully benefit the other users of the gem.
UPDATE 2012.11.16
Axlsx has been updated to version 1.3.4 to provide two class methods on ColorScale to create new ColorScale objects with sensible defaults for two-tone and three-tone color scaling.
Examples:
# to make a three tone color scale
color_scale = Axlsx::ColorScale.three_tone
# to make a two tone color scale
color_scale = Axlsx::ColorScale.two_tone
# To make a customized color scale you, pass hashes consisting of
# type, val and color key-value pairs as arguments to the initializer.
# This example that creates the same three tone color scale as
# Axlsx::ColorScale.three_tone
color_scale = Axlsx::ColorScale.new({:type => :min, :val => 0, :color => 'FFF8696B'},
{:type => :percent, :val => '50', :color => 'FFFFEB84'},
{:type => :max, :val => 0, :color => 'FF63BE7B'})

Storing a MessagePacked hash in Redis

I'm having a problem storing a MessagePacked hash in Redis. I've pasted a test case below. When pulling out the packed data from Redis and unpacking it, the hash is slightly corrupted. This appears to happen when the hash values are beyond a certain length, although I can't say that for sure.
I'm using Redis 2.4.17 (default config), Ruby 1.9.3p194, MessagePack 0.4.7, and the Redis gem 3.0.2. The same problem happens using node, so I'm assuming the problem is within MessagePack or Redis. Any ideas?
require 'redis'
require 'msgpack'
class Test
def self.run(url)
redis = Redis.new
data = {'number' => 13498935756, 'hash' => {'url' => url}}
redis.set('my_key', MessagePack.pack(data))
result = MessagePack.unpack(redis.get('my_key'))
puts result
puts result['hash']['url'] == data['hash']['url']
end
end
Test.run('http://fake.example.com') # works
=> {"number"=>13498935756, "hash"=>{"url"=>"http://fake.example.com"}}
=> true
Test.run('http://fakeurl.example.com') # does not work
=> {"number"=>13498935756, "hash"=>{"url"=>"ttp://fakeurl.example.com"}}
=> false
MessagePack deals in raw bytes, which are marked as 'ASCII-8BIT' encoding. However your packed data is coming back from Redis marked as being in UTF-8 encoding. In order for MessagePack to successfully unpack, you need to force it back to being interpreted as raw bytes.
Therefore, change this line...
result = MessagePack.unpack(redis.get('my_key'))
to something like this...
redis_val = redis.get('my_key').force_encoding('ASCII-8BIT')
result = MessagePack.unpack(redis_val)

Ruby get the size in bytes of an array

I would like to obtain the size in bytes of the content of an array (items) in ruby.
I fill my array like this:
#records.each do |record|
items << { :table => table, :id => record.id, :lruos => record.updated_at }
end
In fact, I want to force sending the Content-Length of this array when I serialize it in JSON:
respond_to do |format|
#response['Content-Length'] = items.to_s.size
format.json { render :json => { :success => "OK", :items => items } }
end
So any idea to do this could be interesting.
(for a reason I don't know the content length is not sent, so I want to force it)
I use Rails 3.0.5.
Like WTP said, you probably intend on returning the size of the JSON representation instead of ruby representation of the array, because the JSON is the actual response to the browser. You can do this by encoding beforehand (yielding a string) and then checking its size.
response['Content-Length'] = ActiveSupport::JSON.encode(items).size
More about JSON serialization and rails
Alternatively, you can also do this by item.to_json.bytesize. This will give you the size of JSON string that is being sent.
For those that are still wondering - I found this to work
ActiveSupport::JSON.encode(items).size.to_s
Which while its many years later - may help someone.

Resources