Formatting DateTime in Rails

  • There are some useful params with Time#to_s
[14] pry(main)> time = u.created_at
=> Thu, 13 Nov 2014 14:21:01 UTC +00:00
[15] pry(main)> time.to_s(:long)
=> "November 13, 2014 14:21"
[16] pry(main)> time.to_s(:short)
=> "13 Nov 14:21"
[17] pry(main)> time.to_s(:default)
=> "2014-11-13 14:21:01 UTC"
[18] pry(main)> time.to_s(:db) #this will put it into the UTC time zone
=> "2014-11-13 14:21:01"
[19] pry(main)> time.to_s(:number)
=> "20141113142101"
[20] pry(main)> time.to_s(:long_ordinal)
=> "November 13th, 2014 14:21"
[21] pry(main)> time.to_s(:rfc822)
=> "Thu, 13 Nov 2014 14:21:01 +0000"
> time.utc.strftime('%FT%TZ')
=> "2016-03-18T18:33:09Z"
  • And for custom formatting, there is a very good post for it:
    https://hackhands.com/format-datetime-ruby/

[Solved] Install Nokogiri on Yosemite with Ruby 2.1.3

Updated to Yosemite and got the following problem while run bundle install with ruby 2.1.3:

An error occurred while installing nokogiri (1.6.1), and Bundler cannot continue.
Make sure that `gem install nokogiri -v '1.6.1'` succeeds before bundling.

The solution is:

gem install nokogiri -v '1.6.1' -- --use-system-libraries=true --with-xml2-include=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/libxml2
Fetching: nokogiri-1.6.1.gem (100%)
Building native extensions with: '--use-system-libraries=true --with-xml2-include=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/libxml2'
This could take a while...
Successfully installed nokogiri-1.6.1
Parsing documentation for nokogiri-1.6.1
Installing ri documentation for nokogiri-1.6.1
Done installing documentation for nokogiri after 3 seconds
1 gem installed

Time Zone in Rails

  • Get All Time Zones
    Use

    ActiveSupport::TimeZone.all.each{|tz| puts "#{tz.formatted_offset}, #{tz.name}"};nil
    -11:00, American Samoa
    -11:00, International Date Line West
    -11:00, Midway Island
    -10:00, Hawaii
    -09:00, Alaska
    -08:00, Pacific Time (US & Canada)
    ... ignore the remaining ...
    

    To list all the built in time zones with Rails

  • Get Specific Time Zone
    Use

    ActiveSupport::TimeZone.new('Eastern Time (US & Canada)')
    

    To get the instance of a time zone with the name listed within the above output

  • Custom Time Zone
    When u know the offset, you can do this via

    ActiveSupport::TimeZone[5.hours + 30.minutes]
    => (GMT+05:30) Chennai
    

    But if the time zone u specified is not supported, it will return nil.

  • Parsing Time with Time Zone
    When u got the time zone using above methods, `time_zone` for example, using

    pry(main)> time_zone.parse('2014-12-30 17:40')
    => Tue, 30 Dec 2014 17:40:00 IST +05:30
    

    To parse a string like time.

  • Convert Time Zone
    Let

    time

    is the time we want to handle,

    target_time_zone

    is the target time zone we want to conver
    Using

    time.in_time_zone(target_time_zone) 

    For example:

    pry(main)> time = Time.zone.now
    => Tue, 30 Dec 2014 09:48:06 UTC +00:00
    pry(main)> time.hour
    => 9
    pry(main)> target_time_zone = ActiveSupport::TimeZone[8.hours]
    => (GMT+08:00) Beijing
    pry(main)> converted_time = time.in_time_zone(target_time_zone)
    => Tue, 30 Dec 2014 17:48:06 CST +08:00
    pry(main)> converted_time.hour
    => 17
    

    For the UTC time zone, the following code:

    time.utc

    is a quick method for converting time into TimeZone ‘UTC’

  • Daylight saving time
    Using

    time.dst?
    

    to check if a time is with daylight saving

Using VCR with WebMock in Rails Rspec Tests

If the application need interaction with another web service, it’s convenience to using VCR with WebMock to test the application, rather than doing the request to another web service every time.

Setup

Modify Gemfile

group :test do
  gem 'webmock'
  gem 'vcr'
end

and don’t forget to run

bundle install

Config VCR

The following code can be placed in the spec_helper.rb

VCR.configure do |c|
  c.allow_http_connections_when_no_cassette = true
  c.cassette_library_dir = 'spec/cassettes' #this specified the directory for placing the record files
  c.hook_into :webmock
  c.configure_rspec_metadata!
  c.default_cassette_options = {
    :record => :once,
    :erb => true,
    :match_requests_on => [:method, :uri, :host, :path, :headers]
  }
end

Using VCR

Then you can using VCR when write the rspec test like:

describe 'Some api call tests', :vcr => true do
#write normal api call tests here
end

Re-record

Sometimes we need to re-record the cassettes, because maybe the request params changed in our app or the response is updated from third-party server.

It’s very easy to do that, just modify your VCR.config block, set record: all instead of :once.

:record => :all

and run your rspec tests related to that cassettes, then the cassettes files will be updated.

And you can specify the matchers per test:

describe 'Something', :vcr => {match_requests_on:[:method, :uri]} do
  # Some tests
end

The following method can tell whether vcr is recording, it’s very useful in some scenarios:

VCR.current_cassette.recording?

[Repost] Here Document in Ruby

This is repost from http://log.gmarik.info/2007/12/rubys-here-document-heredoc-mini.html , good post!

Basics

Here Document(or HereDoc) is a way to declare String literal in Ruby programming language:

some_text = <<END_OF_STRING
 You can write any text here for your document that's why such
 statement is called - HereDoc
END_OF_STRING

That’s it! Now some_text variable points to the string object containing the text going between END_OF_STRING
As you may know HereDoc isn’t a unique Ruby feature, rather it’s a common construct(with some distinctions) for scripting languages “brewed” in Unix environment.

The terminator

By Ruby convention a variable starting with capital letter is a constant. But that’s not a case for the END_OF_STRING from previous example, because terminator is just a string which parser treats as the end of HereDoc.
Well if a terminator is a string then can i use arbitrary(say put spaces within) string as the terminator like end of string? The answer is – yes you can!
<<heredoc is interpreted same as <<"heredoc" (please note double quotes around latter heredoc).
But explicit notation(with quotes) is a bit more powerful.

String interpolation

By explicitly enclosing terminator with quotes you may have:

a_text = <<"Ruby, please end my HereDoc once you find this terminator string"
Hello world!
Ruby, please end my HereDoc once you find this terminator string

or

fuzzy_names = <<">>"
foo, baz, bar
>>

Wow, if i can use double quoted string, then probably i can use single quoted string as well:

puts <<'end of string'
 1+1=#{1+1}
end of string
prints
1+1=#{1+1}

as single quoted strings aren’t interpolated unlike double quoted:

puts <<"end of string"
 1+1=#{1+1}
end of string
prints
1+1=2

Indent modifier

By default HereDoc terminator is expected to be placed on the very beginning of the separate line
By using – on HereDoc declaration, you may indent end terminator arbitrary:

greeting = <<-"here document ends"
                 Hello world
               here document ends

Keep in mind that leading spaces are kept.

Advanced usages

a, b = <<'EOA', <<-EOB
string_a
EOA
string_b
   EOB
is equal to
a, b = "string_a\n", "string_b\n"

At this point i’m thinking about HereDoc as “placeholder” that gets substituted with the string itself. Why is that important? Because you may then treat HereDoc declaration as the actual string and send messages(call methods):

<<'heredoc'.reverse == "\n!dlrow olleH"
Hello world!
heredoc

is a true statement!

STI of ActiveRecord in Rails

STI, Single Table Inheritance, supported by ActiveRecord in rails to let us build the models’ hierarchy on a single data table.

Model description

For example, we have a User model, and have an Administrator model, which inherit from User. we can build just one table named ‘user’, and make sure there is a column named ‘type’ and of string type in the User table. like below:

mysql>describe 'user';
+--------------------------+--------------+------+-----+----------+----------------+
| Field                    | Type         | Null | Key | Default  | Extra          |
+--------------------------+--------------+------+-----+----------+----------------+
| id                       | int(11)      | NO   | PRI | NULL     | auto_increment |
| type                     | varchar(255) | YES  |     | NULL    |                |
| name                     | varchar(255) | YES  |     | NULL     |                |
+--------------------------+--------------+------+-----+----------+----------------+

Code

then, we can writing following code to have a look of STI:

class User < ActiveRecord::Base
    validates_presence_of :name
end
class Administrator < Post
end

just this, and we can verify it in console:

admin = Administrator.create( :name => "admin")
admin.type # "Administrator"
admin.id # 1

Concerns

the STI is enabled by default, and so the 'type' in table is likely reserved for STI and we can not using it for other purpose;
and another problem is that if the shared columns are not so much in the model hierarchy, it's a waste using STI, we prefer to setup another table for the child model.
Luckily, we can disable this feature in a table that not using this feature. by doing this:

class User < ActiveRecord::Base
    self.abstract_class = true
    validates_presence_of :name
end
class Administrator < Post
end

by doing this, the 'type' columns in User can be used at our will and there must another table for Administrator alone.

Referrence

http://ihower.tw/rails3/activerecord-others.html

Typhoeus : a gem for http requests in rails.

Typhoeus



Single request

request = Typhoeus::Request.new(
  "www.example.com",
  method: :post,
  body: "this is a request body",
  params: { field1: "a field" },
  headers: { Accept: "text/html" }
)

# handle the response as follows
request.on_complete do |response|
  if response.success?
    # hell yeah
  elsif response.timed_out?
    # aw hell no
    log("got a time out")
  elsif response.code == 0
    # Could not get an http response, something's wrong.
    log(response.return_message)
  else
    # Received a non-successful http response.
    log("HTTP request failed: " + response.code.to_s)
  end
end

# this will actually execute the request
request.run



Parallel requests
Typhoeus doing well in the parallel requests, just doing this:

hydra = Typhoeus::Hydra.hydra

first_request = Typhoeus::Request.new("www.example.com/posts/1.json")
first_request.on_complete do |response|
  third_request = Typhoeus::Request.new(www.example.com/posts/3.json)
  hydra.queue third_request
end
second_request = Typhoeus::Request.new("www.example.com/posts/2.json")

hydra.queue first_request
hydra.queue second_request
# this is a blocking call that returns once all requests are complete
hydra.run



Referrence
For more information, looking:
Typhoeus on Github