Theory of Coding

Web Development blog

Nested Forms

Nested Forms with RAILS

Nested forms is a form within another form. It’s nice to not jump between the parent and child forms when creating both the parent and the child in the same form. In this example, I’m using Post as a parent and Tags as the child. A Post will have many Tags.

accepts_nested_attributes_for

There is a cool method accepts_nested_attributes_for from ActiveRecord that allows you to save attributes on associated records through the parent. This method gives you the attribute writer, in this case, we got the tags_attributes=(attributes) writer method. You can add allow_destroy: true so if the post is deleted, this tag will be deleted also.

1
2
3
4
class Post < ActiveRecord::Base
  has_many :tags, :through => :post_tags
  accepts_nested_attributes_for :tags, allow_destroy: true
end

The Form

We made form_for for the new Post. We want to make a nested form so that we can create a form for a new Tag also. To do this, we will use fields_for to make a text_field to enter a new tag. We will be making a Tag.new in place for the new tag.

1
2
3
4
5
6
7
8
<%= form_for(@post) do |f| %>
  ..... #other code on the form 
 <%= f.fields_for :tags, Tag.new do |tag_field| %>
  <%= tag_field.label :name %>
  <%= tag_field.text_field :name %>
  <% end %>

 <%= f.submit %>

Params

Imgur

See how if you inspect element, this new tag text field is called tags_attributes? This came from the cool method accepts_nested_attributes_for in the Post model. This automatically gives you nested params post[tags_attributes][0][name]. Although we did fields_for :tags, it gives you tags_attributes in the params for free. It is also [0] because this is the first tag we’re making, but you can certainly enter more tag inputs if you wish.

To allow this in our params, we will do add tags_attributes with the name field.

1
2
3
4
private
def post_params
    params.require(:post).permit(:name, :content,:tags_attributes =>[:name],:tag_ids => [])
end

As a reminder, we made post_params as a private method so that we can do mass assignment, and prevent a hacker from editing the params and changing something in our forms that we didn’t want to change.

Now this will allow us to get a nested hash in our params that’s part of Post. "tags_attributes"=>{"0"=>{"name"=>"mrkittycat"}}},

1
2
3
4
5
6
7
8
9
10
{"utf8"=>"✓",
 "authenticity_token"=>"r/vgXWbzduyZIQxVetNzcDJEt3CbDX4Js2oclxXYq5eUjmZdoRCB+PP17xoBPuIQkJPHCWRzmaBTQ/1vH6WfIA==",
 "post"=>
  {"name"=>"The new post name",
   "content"=>"yay writing a new post",
   "tag_ids"=>["1", "100", ""],
   "tags_attributes"=>{"0"=>{"name"=>"mrkittycat"}}},
 "commit"=>"Create Post",
 "controller"=>"posts",
 "action"=>"create"}

def create

Now that we got the params we want, we have to actually create the new tag.

Once the form is submitted, this will go to the def create method of the Post controller, because it is sending a post request to the server.

1
2
3
4
def create
  @post = Post.new(post_params)
  #other code here
end

We will do Post.new and put in the post_params from our private method, and it will set its attributes to whatever we provided in the params.

It will ALSO set the :name to the newly created tag, and associate this tag to this particular post. This was made possible because of the accepts_nested_attributes_for method in our Post model.

Imgur

Great! Now we have the tag that we just created– mrkittycat.

That’s the gist of it. This allowed me to create a new tag and associate it with this post, without making separate forms. It comes in handy at times.

To read more about nested forms, here is some documentation about it from ApiDock

Refactoring

Refactoring Code

Why refactor?

After spending hours writing this piece of code, why would you want to go back to spend more time on refactoring it? It already works! Dealing with the big chunk of code you just wrote seems daunting and tiresome, but it is necessary for adding new features without making huge changes to existing code. Also, it is just easier to read and easier to go back to when you read it again in the future. Depending on what you wrote, there are millions of ways to refactor, but this post just shows what I did to refactor my 28 line method into 12 lines of code. You can check out Sandi Metz’s video ‘All the litting things’ to get better at refactoring.

Make it go green first

Before refactoring, you must have the code working first. No matter how messy and ugly your code is, just make it work. Make the test pass green!

Here is some code I wrote for the Green Grocer lab, where the apply_coupons method take in a cart and coupon hash argument, and applying the coupon on the cart items if applicable. It should return a hash of the items with the correct quantity, and the “item name W/COUPON” with the discount.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def apply_coupons(cart:[], coupons:[])
    apply_coupons_hash = {}
      coupon_items = [] # get coupon item names
        coupons.each do |item|
          coupon_items << item[:item]
        end
    cart.each do |item|
      name = item[0]
      attributes = item[1]
      num_of_coupon = 0
      coupon_price = 0
      coupons.each do |coupon_hash| #get num and cost of that particular item from coupons hash
        if coupon_hash[:item] == name
          num_of_coupon = coupon_hash[:num]
          coupon_price = coupon_hash[:cost]
        end
      end
      num_of_coupon #quantity of item required for coupon to work

      if ((coupon_items.include?(name)) && (attributes[:count] >= num_of_coupon))
      #for the current item, if the count is >= coupon quantity requirement
      #decrease the item count and add the coupon hash 
      quantity = (attributes[:count] / num_of_coupon) #item quantity/coupon quantity
        apply_coupons_hash[name] = {:price => attributes[:price], :clearance => attributes[:clearance], :count =>(attributes[:count] - (num_of_coupon * quantity))}
        apply_coupons_hash[name + ' W/COUPON'] = {:price => coupon_price, :clearance => attributes[:clearance], :count => quantity}
      else #if no coupon for this item, then just add the existing item hash to apply_coupons_hash
        apply_coupons_hash[name] = {:price => attributes[:price], :clearance => attributes[:clearance], :count => attributes[:count]}
      end
    end
    apply_coupons_hash
 end

This monstrous piece of code is 28 lines long… No way am I going to remember what each part does a week later.

Here is my refactored version of the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def apply_coupons(cart:[], coupons:[])
    apply_coupons_hash = {}
    cart.each do |item|
      item_hash = build_item_hash(item)
      matching_coupon_for_item = coupons.detect {|coupon| coupon[:item] == item_hash[:name]}
      if matching_coupon_for_item && can_apply_coupon?(item_hash, matching_coupon_for_item)
        quantity = (item_hash[:count] / matching_coupon_for_item[:num])
        apply_coupons_hash[item_hash[:name]] = {:price => item_hash[:price], :clearance => item_hash[:clearance], :count =>(item_hash[:count] - (matching_coupon_for_item[:num] * quantity))}
        apply_coupons_hash[item_hash[:name] + ' W/COUPON'] = {:price => matching_coupon_for_item[:cost], :clearance => item_hash[:clearance], :count => quantity}
      else
        apply_coupons_hash[item_hash[:name]] = {:price => item_hash[:price], :clearance => item_hash[:clearance], :count => item_hash[:count]}
      end
    end
    apply_coupons_hash
end

It’s only 12 lines long compared to my 28 line code before!! There is hope.

Change data structure to fit your needs

I can totally get rid of these lines of code if I had the data structure I wanted.

1
2
3
4
5
6
cart.each do |item|
      name = item[0]
      attributes = item[1]
      num_of_coupon = 0
      coupon_price = 0
      coupons.each do |coupon_hash| #get num and cost of that 

The reason why I set variables for those things, was because the current array I’m getting from |item| is this

1
["AVOCADO", {:price => 3.0, :clearance => true, :count => 2}]

I had to do item[0] to get the name of the item, and etc,. All I wanted to do here was to get the information from the item so I can use it later in my if statement. These 4 lines of code can be replaced into 1 if I had the data structure to simply say something like item_hash[:name] to JUST get the name.

1
2
3
4
5
6
cart.each do |item|
  item_hash = {}
  item_hash[:name] = item_array.first
  item_hash.merge!(item_array.last)
  #this is the return value
  #=> {:name=>"AVOCADO", :price=>3.0, :clearance=>true, :count=>2}

Don’t be afraid to make new methods

Knowing the single responsibility rule, getting the item hash seems like it should be it’s own method. Rebuilding the datastructure is for our own ease, and has nothing to do with apply_coupons. Don’t worry about adding more methods and adding more lines of code. This is usually the result of refactoring; abstracting parts away into their own methods make them reusable and clear to the reader what this function is doing.

1
2
3
4
5
def build_item_hash(item_array)
  item_hash = {}
  item_hash[:name] = item_array.first
  item_hash.merge!(item_array.last)
end

Now that we dumped that into it’s own method, our cart.each do looks a litle bit better.

1
2
cart.each do |item|
      item_hash = build_item_hash(item)

Now, I tried to iterate over coupons to grab the coupon that matches the current item name, so that I can check if items in the cart meet the coupon requirement.

1
2
3
4
5
6
7
8
9
coupons.each do |coupon_hash| #get num and cost of that particular item from coupons hash
        if coupon_hash[:item] == name
          num_of_coupon = coupon_hash[:num]
          coupon_price = coupon_hash[:cost]
        end
      end
      num_of_coupon #quantity of item required for coupon to work

      if ((coupon_items.include?(name)) && (attributes[:count] >= num_of_coupon))

Look for specialized methods to do the job

Sure, you can use the broad .each method on anything, but there are many methods out there that you can use that will make your life easier. Here is a list of ruby methods for reference! You can see methods you can use for arrays, strings, etc,.

Instead of iterating through the coupons to check if the item name matched with the coupon name, and then returning the quantity requirement (num) for the coupon, I can just approach this differently and just use a more specialized method, ‘detect’ to see if the coupon exists for this item.

1
matching_coupon_for_item = coupons.detect {|coupon| coupon[:item] == item_hash[:name]}

Those 6 lines just turned into a 1 liner, after using .detect instead of .each

Writing code I wish I had

Sometimes if you don’t know what to write, you can start by writing a method that you wish you had, and then try to make the method!

1
if ((coupon_items.include?(name)) && (attributes[:count] >= num_of_coupon))

After all of the refactoring I did above, I FINALLY reach my if statement to see if there is a coupon that matches the current item, AND see if the quantity requirement of the coupon was met by the item count. If someone was reading this, they’d have to find out what attributes is , and what num of coupon means also. Wouldn’t it be nice to just write “can apply coupon?” ?

1
2
3
def can_apply_coupon?(item_hash, matching_coupon_for_item)
  (item_hash[:count] >= matching_coupon_for_item[:num])
end

I made this into a new method. Although it did not decrease my lines of code, it did make it clear what I was trying to do in my if statement.

1
if matching_coupon_for_item && can_apply_coupon?(item_hash, matching_coupon_for_item)

Now, I can proceed to do what I wanted to do all along, for this one apply coupons method. For the refactored version, you can see the resulting method goes straight into just applying the coupons to the cart and returning the new hash if there was a coupon that exists and if the requirement is met.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def apply_coupons(cart:[], coupons:[])
    apply_coupons_hash = {}
    cart.each do |item|
      item_hash = build_item_hash(item)
      matching_coupon_for_item = coupons.detect {|coupon| coupon[:item] == item_hash[:name]}
      if matching_coupon_for_item && can_apply_coupon?(item_hash, matching_coupon_for_item)
        quantity = (item_hash[:count] / matching_coupon_for_item[:num])
        apply_coupons_hash[item_hash[:name]] = {:price => item_hash[:price], :clearance => item_hash[:clearance], :count =>(item_hash[:count] - (matching_coupon_for_item[:num] * quantity))}
        apply_coupons_hash[item_hash[:name] + ' W/COUPON'] = {:price => matching_coupon_for_item[:cost], :clearance => item_hash[:clearance], :count => quantity}
      else
        apply_coupons_hash[item_hash[:name]] = {:price => item_hash[:price], :clearance => item_hash[:clearance], :count => item_hash[:count]}
      end
    end
    apply_coupons_hash
end
# returns the new hash of the updated cart after coupons are applied
#=> {"AVOCADO"=>{:price=>3.0, :clearance=>true, :count=>0},
#=>  "AVOCADO W/COUPON"=>{:price=>5.0, :clearance=>true, :count=>1}}

In summary, these are things you should keep in mind when refactoring:

  • Make it go green first
  • Change data structure to fit your needs
  • Don’t be afraid to make new methods
  • Look for specialized methods to do the job
  • Writing methods I wish I had

Don’t freak out when your tests turn red, it’ll take a while before it turns green again, but it’s worth it.

In general, when you use .each and your code looks like a sandwich, you should be thinking of other iterators that is made specifically for the type of function you’re trying to do.

1
2
3
4
5
new_array = []
[1,2,3,4,5].each do |numbers|
  new_array << numbers.even?
end
new_array

In this sandwich, you set a new empty array, do the iteration to grab stuff and put it into the empty array, and then return the new array. This can be easily done with select, or collect.

1
[1,2,3,4,5].select { |num|  num.even?  }

Most of the time, when there is duplication of code, you can probably abstract it away into a method. However, don’t make the wrong abstraction. It’s better to have duplication than the wrong abstraction. As Sandi Metz says, it’s like surfing farther and farther out into the ocean, when you’re doing the wrong abstraction.

When writing code, always try to be explicit as possible, because it’ll make it easier for other people to understand your code. You can use comments to explain what you’re doing here, but try to make your code so clear that comments are not needed at all to explain what you’re trying to do.

I only recently started refactoring code, but I hope you’ll keep these things in mind when you decide to refactor. Sandi Metz gave a talk on refactoring called ‘All the litting things’ and you should check it out to get better at it! Here is a cheat sheet on refactoring.

In-App Messaging

Building a Messaging System

After trying to deploy to heroku with an in-app messaging system with the mailboxer gem, the messaging system seemed to be broken. After trying to fixing it for 4 hours, with a lack of documentation on it on the internet, I decided to build my own messaging app from scratch.

This messaging system was built for my project, CampusBazaar, which allows users to message sellers about items to ask questions or to pick places to meet up on campus. Just thinking about how to organize the app was the most difficult part of the app. Knowing how the messaging app is associated with other parts of the app is important.

For my purpose, I wanted a messaging system that knows about the item that the sender is inquiring about. Any time someone inquires about an item, a new conversation is started between the two users. If the user inquires about another item from the same user, there will be a separate conversation, because it solely based on the item.

Basically, this is what should happen You will click on Contact seller button on the item show page Imgur

Then, a new conversation will be started between you two. This means the message form will be nested inside the conversation form Imgur

Lastly, this will be the messaging app containing all your conversations, and you can see all the messages that belong to that particular conversation. Imgur

To start, we should make a migration for conversations. Essentially, there will be a conversation between two users, and it is connected to an item. This is basically a join table.

1
2
3
4
5
6
7
8
9
10
class CreateConversation < ActiveRecord::Migration
  def change
    create_table :conversations do |t|
      t.integer :user1_id
      t.integer :user2_id
      t.integer :item_id
      t.timestamps null: false
    end
  end
end

Here, we have the messages migration. There will be a sender_id and recipient_id and not a user1_id and a user2_id like in the conversation migration because it matters who is the sender or not, whereas in the conversation migration, it is just two people talking to each other, regardless of who sent the message first, or who is the sender or recipient. Each messsage will belong to a conversation, hence the conversation_id.

1
2
3
4
5
6
7
8
9
10
11
12
class CreateMessage < ActiveRecord::Migration
  def change
    create_table :messages do |t|
      t.integer :sender_id
      t.integer :recipient_id
      t.integer :conversation_id
      t.text :content
      t.boolean :read, :default => false
      t.timestamps null: false
    end
  end
end

Now for the associations. This is the conversation model. It will belong to a item, the users that are talking to each other, and has many messages. It belongs to a user with a foreign key of class name ‘User’ so that we can do ask the console about the user of that conversation when doing Conversation.user1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Conversation < ActiveRecord::Base
  belongs_to :item
  belongs_to :user1, :foreign_key => :user1_id, :class_name => 'User'
  belongs_to :user2,:foreign_key => :user2_id, :class_name => 'User'
  has_many :messages

#self is the conversation itself, from the message form @conversation
  def recipient(current_user)
    if (current_user.id == self.user1_id)
      self.user2_id
    else (current_user.id == self.user2_id)
      self.user1_id
    end
  end
end

This isthe messsage associations. It will belong to a conversation, also belong to a recipient and sender, associating that with the User class like in the Conversation model with foreign keys. The message will also belong to a sender. There will be many people inquiring about an item, but there will only be one buyer, who is actually going to buy the item.

1
2
3
4
5
6
class Message < ActiveRecord::Base
  belongs_to :conversation
  belongs_to :recipient, :foreign_key => :recipient_id,:class_name => 'User'
  belongs_to :sender, :foreign_key => :sender_id, :class_name => 'User'

end

Remember that if you have a belongs_to association, the counterpart will have a has_many associtation. A user will have many items and conversations as user1 or user2.

1
2
3
4
5
6
class User < ActiveRecord::Base
  belongs_to :community
  has_many :items, :foreign_key => 'seller_id'
  has_many :offers_sent, :class_name => "Offer", :foreign_key => 'buyer_id'
  has_many :conversations, :foreign_key => 'user1_id'
  has_many :conversations, :foreign_key => 'user2_id'

Finally, the item will have many conversations, because the conversation also belongs to an item. There will be many inquiries from potential buyers but there will just be one buyer.

1
2
3
4
5
6
7
8
9
class Item < ActiveRecord::Base
  attr_accessor :delete_product, :delete_avatar

  belongs_to :seller, :class_name => 'User'
  delegate :community, to: :seller
  has_many :item_categories
  has_many :categories, through: :item_categories
  has_many :offers
  has_many :conversations

Let’s not forget about our routes. There will be messages nested under routes, but only the GET request of index and POST of create will be needed because we will show all the messages for that particular conversation, and we need to create new messages. There will be no need of other routes such as the Show method because we will not be showing each individual message.

1
2
3
  resources :conversations do
    resources :messages, only: [:index, :create]
  end

Now, understanding that we will click Contact Seller from the items page, it will do a GET request to go to the new_conversation_path to see the form to create a new conversation. We will nest the message form inside the conversation form because upon creation of a conversation, there should be a message.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class ConversationsController < ApplicationController

  def index
    @users = User.all
    @conversations = Conversation.all
  end

  def create
    @conversation = Conversation.new(conversation_params)
    @conversation.save
    @message = Message.new
    @message.conversation_id = @conversation.id
    @message.recipient_id = @conversation.user2_id
    @message.sender_id = @conversation.user1_id
    @message.content = params[:conversation][:messages][:content]
    @message.save
    redirect_to conversations_path
  end

  def new
    #binding.pry
    @item = Item.find(params[:item_id])
  end

private
  def conversation_params
    params.require(:conversation).permit(:user1_id, :user2_id, :item_id, :content)
  end

end

This is the form. I added hidden fields to pass into private params in th controller. Once the form is submitted, it will send a POST request to the server and do its thing at the def create in the Conversation Controller. The params will be set in the new instance Conversation and saved, and a new message will also be created with all the passed in information.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%= form_for Conversation.new do |f| %>
  Seller: <%= @item.seller.name%><br>
  Buyer: <%= current_user.name %><br>

  Message for item: <%= @item.name %><br />

  <%= f.hidden_field :item_id, :value => @item.id%>
  <%= f.hidden_field :user2_id, :value => @item.seller.id%>
  <%= f.hidden_field :user1_id, :value => current_user.id%>
#this is the nested form
  <%= f.fields_for :messages do |message_form| %>
  <%= message_form.label :content %>
  <%= message_form.text_area :content, :rows => "5", placeholder: 'Write your message here'%><br />
  <% end %>
  <%= f.submit 'Send Message' %>
<% end %>

Once that conversation is created, it will redirect to the def index, to see all their conversations they ever had. If they clicked on a conversation, it will basically send a GET request to the Messages Controller to give back the index page of the messages pertaining to that conversation, given that the id of the conversation is passed in.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class MessagesController < ApplicationController

  def index
    @conversation = Conversation.find(params[:conversation_id])
    @recipient = @conversation.recipient(current_user)
    @messages = @conversation.messages
    respond_to do |format|
        format.html {}
        format.js {}
      end
  end

  def create
    @message = Message.new(message_params)
    @message.save
    redirect_to conversation_messages_path
  end

private
  def message_params
    params.require(:message).permit(:conversation_id, :recipient_id, :sender_id, :content)
  end

end

Where it’s actually going is /conversations/:id/messages, so params will have the id of the conversation. Javascript was used to render the partials so that when you click on the conversation, it will allow ajax to render the messages, without the page ever refreshing.

Imgur

Amazons3 + Paperclip

Amazon S3 with PaperClip with Rails

CampusBazaar

I’m currently working on our second project, CampusBazaar, a rails app that allows students to sell their items with their fellow students at their campus. It provides them a way to organize a small shop to sell things that they may not need when moving, or just things in general, such as clothes, mattresses, etc. Upon registration with a .edu email, they are added to their school community. Since pictures are much needed for the item listings, the Paperclip Gem by thoughtbot was used. For installation, just click on the link above.

1
gem 'paperclip'

Why Amazon S3?

When we pushed to Heroku, we realized that the pictures from our database did not stay on the site; it eventually turned into a broken link photo within 5 minutes. It was time to host the pictures externally, because heroku’s dyno restarts, and the image is lost after that. A more stable way is to upload an image directly from the client side and just save the reference url to the database.

  1. You don’t have to use up lots of storage space on your app.
  2. Pulling images from the rails stack every time will make your app super slow.
  3. It will disappear from Heroku anyway
  4. Amazon S3(Simple Storage System) is cheap, it’s free for 12 months, or until 5 GB is used, or 20,000 GET or 2,000 PUT Requests.
  5. After your free tier is over, you can get it for $0.03 per GB for the first 1 TB/month.

Amazon S3

Installation

1
gem 'aws-sdk'

Assuming paperclip was already properly set up, bundle install the ‘aws-sdk’ gem now.

First, get an Amazon S3 account and create a :bucket for your app. You will also need your Amazon Access Key and the Amazon Secret key.

I saved my keys in my application.yml file. This file will not be pushed to github, so don’t worry about people stealing your keys. You must set up the figaro gem to use this feature. Remember to put your key in single quotes ‘ ’, and not double quotes “ ”.

1
2
3
4
# config/application.yml
  amazon_access_key: 'INSERT YOUR KEY HERE'
  amazon_secret: 'INSERT YOUR KEY HERE'
  amazon_bucket_name: 'INSERT YOUR BUCKET NAME HERE'

From then on, I encountered some problems. I searched around google to find out how to set up Amazon S3 with paperclip, and every post seems to have a different answer. There were two posts that were helpful, but did not work for me. It was possible that since my keys were stored in my application.yml file that was not uploaded, it was not able to access my keys. You can try these posts, thoughtbot or devcenter.heroku to see if they work for you. If not, you can follow my tutorial below.

In my config/environments/production.rb, I put the code below. As a reminder, you can get your keys from your application.yml file by using calling ENV[‘whatever you named your key’]. ex. ENV[‘amazon_secret’]

We’re specifying the AWS configuration variables so that we can use it when your app is in production when its up on heroku.

1
2
3
4
5
6
7
8
9
# config/environemnts/production.rb
config.paperclip_defaults = {
  :storage => :s3,
  :s3_credentials => {
    :bucket => ENV['amazon_bucket_name'],
    :access_key_id => ENV['amazon_access_keys'],
    :secret_access_key => ENV['amazon_secret']
  }
}

Then, I put my paperclip config in the development.rb so that I can test it out during development in my localhost:3000

1
2
3
4
5
6
7
8
# config/environments/development.rb
  config.paperclip_defaults = {
  :storage => :s3,
  #:s3_host_name => 'REMOVE_THIS_LINE_IF_YOURE_IN_THE_US',
  :s3_credentials => {
    :bucket => 'YOUR BUCKET NAME'
  }
}

Then, create a aws.yml file in your config directory, if it was not automatically loaded by aws-sdk. You can put different keys in here if you want to

1
2
3
4
5
6
7
8
# config/aws.yml
development:
  access_key_id: ENV['amazon_access_key']
  secret_access_key: ENV['amazon_secret']

production:
  access_key_id: ENV['amazon_access_key']
  secret_access_key: ENV['amazon_secret']

This will be pushed to github, so don’t try to just write your keys here. People will be able to steal your keys. Don’t try to put this in your .gitignore file either, this is essential for the Amazon S3 to work. Just use ENV to grab your keys from your application.yml file.

Lastly, you must add your AWS configuration variables onto heroku in your settings, or you can do it through the command line. Just remember to call the keys the same way you called it in your app. Once you push to heroku master, everything should work.

1
2
3
$ heroku config:set amazon_bucket_name=your_bucket_name
$ heroku config:set amazon_access_key=your_access_key_id
$ heroku config:set amazon_secret=your_secret_access_key

To check whether or not it was successful, on your localhost, do inspect element on your uploaded photo, and see if the url is an amazon url. Then, in production on heroku, also check to see if the url is an amazon url. If it is, then congratulations, you have successfully set up Amazon S3. Happy uploading.

Gon Gem

Gon Gem

gon

We’ve started project mode this week and it’s been pretty cool building our own apps without any tests to pass, and solve real world problems with our application. I’ve learned a lot of new things and one of them new gems I learned to make my life easier is the Gon Gem!

Why Use Gon?

Gon is a ruby gem that you can use to send some data to your javascript files without getting it from your views and parsing it. It’s quick and easy and will save you a lot of time trying to connect the path from getting it to your javascript file. YOu can renew data in your variables through ajax with gon.watch, and it also supports Jbuilder, Rabl, and Rabl-Rails. You can learn more about Gon by click on the link above.

How I encountered the problem

While I was working on our project on using the foursquare API to find the BEST places to eat – not just random restaurants around you, but venues that people keep going back to, I encountered the problem of parsing jSON from the Geonames API. In my javascript file, I was trying to display the location of your city and zipcode, by using the longitude and latitude of your current location. But before I can even parse it, I have to put in my username for the API and since I didn’t want hackers on github to hack my API key, I wanted to put it in the figaro file, which loads its values to ENV and puts it in .gitignore. I wanted to access my API key from my ENV and put it to my javascript file, but it was really hard to.

Initial efforts

Maybe we can just pull the ENV into a variable! WRONG

1
var username = ENV['geonames_username']

Maybe we need to interpolate it, this is from a ruby file, afterall. I changed the searches.js file into searches.js.erb so I can write ruby in it. In my file, I tried to set the api key to a variable username. WRONG

1
var username = <%= ENV['geonames_username'] %>

Then I tried to concatenate it into my API link to parse. WRONG

1
var link = "http://api.geonames.org/findNearestAddressJSON?lat=" + latitude + "&lng=" + longitude + "&username=" + username

Apparently, that still gave me nothing. my var username was just an empty string, which resuilted in a bad API link.

Here is where the Gon Gem came in. One of our instructors, Sophie, recommended this gem, which made it much easier to access data to my javascript file, because I was not able to get data from the ENV. It was pretty simple to set up also.

With the Gon Gem

In your Gemfile, you will add the gem

1
gem 'gon'

Then you will bundle install to install the gem into your computer. If you haven’t already, add the api key to your application.yml from your figaro gem, like you usually would for regular ruby. Make sure it is in single quotes ‘’ and not double quotes “ ”, I made the mistake of using double quotes and it was not taken well when you ask for it in your model when you do ENV[‘api_key’].

To access it in your javascript file, go to the controller where you are trying to use the api key on that page and define it so your js file can grab it from the controller.

1
2
3
4
def index
  @search = Search.new
  gon.username = ENV['geonames_username']
end

In your javascript file, you can set the variable username to gon.username

1
var username = gon.username

Now this will work and you can continue parsing your data efficiently!

1
var link = "http://api.geonames.org/findNearestAddressJSON?lat=" + latitude + "&lng=" + longitude + "&username=" + username

The Gon gem has been useful to me. Although this was a relatively easy problem to fix, there are probably other harder and deeper problems you can use it with that is best suited for this gem. For more information the typical uses and what you can use it with, you can go here! Gon gem

Tale of Two Languages

Ruby vs. Javascript

Tale of Two Languages

Ruby and Javascript are very difference languages in many ways such as their syntax, methods, and ways of defining functions. Ruby tends to be shorter and more compact but javascript seems to be more explicit in defining their values such as putting function(), and var in front of the object. Both are object oriented programming languages, where they have a class and objects and methods that associates with them are organized in a proper way.

Functions

Javascript has two ways of defining functions

  • function expressions
  • function declarations

Here is a function declaration

1
2
3
  function cat() {
    prompt("Do you like cats?")
};

Here is a function expression

1
2
3
  var cat = function(){
    prompt("Do you like cats?)
  };

Ruby on the other hand, has three types of functions

  • blocks
  • procs
  • lambdas

Here is a block

1
[1,2,3].each { |x| puts x*2 }

Here is a proc

1
2
p = Proc.new { |x| puts x*2 }
[1,2,3].each(&p)

Here is a lambda

1
2
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

Procs and lambdas seem to be closer to a function expression in javascript, because you can set a block to a variable and then call it later.

Iterations

In Ruby:

1
2
3
4
arr = [1, 2, 3, 4]
for item in arr
    puts item
end

In Javascript:

1
2
3
4
var arr = [1, 2, 3, 4];
  for (var i = 0, len = arr.length; i < len; i++) {
    console.log(arr[i]);
}

In this way, javascript seems to be more explicit in showing the types of each element of the method. Javascript specifies var for the variable, and also it lists out the variable to start iteration, the condition for the loop to run, and what happens after each iteration.

Since ruby and javascript are quite different they also have similar methods, that are sometimes called different things but mean the same thing.

Ruby Javascript
push push
reverse reverse
map map
index indexOf
all? every
any? some
slice slice
each forEach
index indexOf
split split
has_key? hasOwnProperty
to_i parseInt
.class typeof()

Methods that do not exist in Javascript:

  • include?

Other Comparisons:

Ruby Javascript
puts console.log()
nil, false 0, null, false, “”, undefined, NaN

Return is usually used in Javascript, but not in Ruby, because Ruby returns the value of the last line in the method. Javascript will not return it without it explicitly being called return.

Arrays

1
2
3
4
5
 Ruby              vs.       Javascript
| a = ["1", "2"]             | var a = ["1", "2"];|
|a.push("3")                 | a.push("3"); |
|a.all?{|n| n > 4}           | a.every(function(n) { return n > 4; });
|a.each {|n| puts n}         |a.forEach(function(n) { console.log(n); })

Hashes

1
2
3
4
5
6
7
8
9
10
11
12
 Ruby:
hashPetName = { "dog" => "Rex", "cat" => "Mistigri" }

hashPetName['dog'] = "Rex"

Javascript:
var hashPetName = {
    dog: "Rex",
    cat: "Mistigri"
  }

hashPetName['dog'] = "Rex";

Functions

1
2
3
4
5
6
7
8
9
Ruby:
def sample_func
  puts "Hello World"
end

Javascript:
function sample_func() {
  console.log("Hello World");
};

Classes

Javascript’s equivalent to Ruby’s class is called a Prototype. To make a new Prototype, just create a new function with a name with aguments.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Ruby:
class Person
  attr_accessor :firstName, :lastName

  def initialize(firstName, lastName)
    @firstName = firstName
    @lastName = lastName
  end

Javascript:
function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

Math

1
2
3
4
5
Ruby:
[-5, 15, 20].reduce(0, &:+) # 30

Javascript:
[-5, 15, 20].reduce(function(sum, value) { return sum + value; }, 0) // 30

Associations

Active Record and Associations with Sinatra

Sinatra

Sinatra is a domain specific language that wraps HTTP requests and responses on top of Rack. Sinatra is similar to Ruby; they are both web frameworks. Sinatra is used for smaller web applications.

When you want to build something, like say a web application where a user can submit a blog post, ActiveRecord is a great framework to use to keep track of databases and their data, and also their associations.

Here is a sample migration for creating the posts table. author_id is the association of the posts to the author.

1
2
3
4
5
6
7
8
9
class CreatePosts < ActiveRecord::Migration
  def change
    create_table :posts do |t|
      t.string :title
      t.text :content
      t.integer :author_id
    end
  end
end

Eventually you will have a database that will look something like these charts, filled with seed data.

Posts Table

id title Content Author_id
1 “cats” “meow meow” 1
2 “dogs” “woof woof” 2

Author table

id author
1 “Mr Kitty”
2 “Mr Puppy”

Tags Table

id tag
1 cats
2 dogs
3 parks

Post_tags table —> needed because posts has many tags, and tags has many posts, so there must be a join table created to satisfy those requirements. It is not simply just a table that either has_many or belongs_to anymore.

id post_id tag_id
1 1 1
2 2 2
3 2 3

So here, the first blog post called “cats” will have the tags cats. But for the second blog post called “dogs” it will have the tags dogs, and also parks.

Now here are the models

1
2
3
4
5
class Posts < ActiveRecord::Base
  belongs_to :author
  has_many :post_tags
  has_many :tags, through: :post_tags
end

because the posts table has “author_id”, which means that posts belongs to an author, and an author will have many posts. Also, you must write “has_many” “:post_tags” so you can mention the join table before mentioning that posts “has_many” tags through the join table.

1
2
3
class Author < ActiveRecord::Base
  has_many :posts
end
1
2
3
class Tags < ActiveRecord::Base
  has_many :posts
end
1
2
3
4
class PostTags < ActiveRecord::Base
 belongs_to :post
 belongs_to :tag
end
1
2
3
4
class Tag < ActiveRecord::Base
  has_many :post_tags
  has_many :posts, :through => :post_tags
end

Some tips:

When writing belongs_to for a class, whatever it belongs to will typically have “has_many”.

eg. class Author “has_many” posts, while Posts “belong_to” Author

When associating with join tables, mention the join table, and then write “has_many” something through the join table in the next line. eg. Like so in “class Posts” above.

Provided that you have seed data, and that you want to associate a post with an author, you can first think about the author as the parent, and posts as the child (because posts belongs to an author, and an author has many posts.)

1
2
3
4
5
6
# In a console, possibly in pry, 
author = Author.find(1) #=>in Author class, find the author with id 1. Now author is set to the Author object with id 1.
post = Post.find(2) #=>in Post class, find the post with id 2 and set it to the variable post.
author.posts #=> []  this gives you an empty array right now.
author.posts << post  #=> shovel in the post with #2 to the author.posts array
author.posts #=>Now will include the Post object of id 2.

When associating with Sinatra, if the model of is associated with another model, you can write that association inside the Controller. If there was a blog controller with Sinatra:

1
2
3
4
5
6
7
8
9
10
11
class BlogController < ApplicationController
  get '/' do
    @blogs = Blog.all
    erb: :'/blogs/index'
  end

  get '/blog/new' do
    @authors = Author.all
    erb: :'blogs/new'
  end
end

In the blogs controller, if you wanted to create a new blog post and went to the form to input the new blog post data, you can also asisgn it to an author, to have an author association too. As long as you associated with authors in the post model, you can access it.

My First Post on Octopress

1. Introduction

2. .tap for Ruby

scroll to the end to read about .tap for Ruby

Why am I at Flatiron?

Hi there! My name is Minling and I just graduated with a bachelors in Biomolecular Sciences. Although I love biology and its cute little microorganisms, I was always into technology. More often times than not have I said “wow wouldn’t it be cool if I built this…”, “oh wait nevermind, I don’t even know how to get code.”

Time is a limited resource, and if lost, it will never be found.

With a finite number of heartbeats in a lifetime, and a finite amount of hours in a day, there is just absolutely no time to waste. People ponder for a long time whether they have taken that risk, but that is just too much time spent being indecisive. Nike just do it

What if you just did it?

If you fail, it’ll be a great lesson to learn, but if you don’t, you win.

“Any chance not taken is an opportunity missed.” ― Ken Petti

Of course it is said easier than done. You can sit there all day looking at motivational quotes but until you make that first step, you aren’t actually listening to any of it.

Some people have lateness issues but it isn’t because they don’t care enough to change, or respect other people’s time. They may have other issues in their life that prevents them from realizing the importance of being on time. No matter how much they are told to be on time, they will never be on time, because they have’t gotten to that realization yet. People can’t be progammed to change, it is up to their own will.

There are people who are creators and others who just want to experience the creations. I want to be a creator of beautiful things. I want to build meaningful, memorable apps that would make someone’s life easier or something cool that people would use. I want to make a dent in this world with my creations.

Sometimes when times get hard, I fall back to pondering whether I have made the right decision, because I made a drastic change in my life to learn to code. I could have stayed in biology and tried to go forward in my career, but I wouldn’t be able to bring my crazy ideas to reality. I guess I’ll never know until it all happens.

“You can’t connect the dots looking forward; you can only connect them looking backwards. So you have to trust that the dots will somehow connect in your future. You have to trust in something — your gut, destiny, life, karma, whatever. This approach has never let me down, and it has made all the difference in my life.”

~ Steve Jobs

#tap dat …

A few times I encountered the usage of #tap in Ruby.

tap{|x|…} → obj

Yields self to the block, and then returns self. The primary purpose of this method is to “tap into” a method chain, in order to perform operations on intermediate results within the chain.

Although that is the definition of the Ruby Doc, it isn’t quite clear on how to use it, at least it wasn’t clear to me.

Essentially, this is what .tap does

1
2
3
4
5
6
class Object
  def tap
    yield self
    self
  end
end
1
2
3
4
5
6
def cats
  array = ['paws', 'furry', 'cute']
  array.reverse!
  array
end
#=> ["cute", "furry", "paws"] 

Using .tap will achieve the same in one line.

You can use the object to do something, and then it wil return itself at the end.

1
2
3
4
def cats
  ['paws', 'furry', 'cute'].tap(&:reverse!)
end
#=> ["cute", "furry", "paws"] 

cats Kitty: “Smells like a good method.”