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.
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.
12345678
<%= form_for(@post) do |f| %> ..... #other code on the form <%=f.fields_for:tags,Tag.newdo|tag_field|%> <%= tag_field.label :name %><%= tag_field.text_field :name %> <% end %> <%=f.submit%>
Params
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.
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"}}},
12345678910
{"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.
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.
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
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.
defapply_coupons(cart:[],coupons:[])apply_coupons_hash={}coupon_items=[]# get coupon item namescoupons.eachdo|item|coupon_items<<item[:item]endcart.eachdo|item|name=item[0]attributes=item[1]num_of_coupon=0coupon_price=0coupons.eachdo|coupon_hash|#get num and cost of that particular item from coupons hashifcoupon_hash[:item]==namenum_of_coupon=coupon_hash[:num]coupon_price=coupon_hash[:cost]endendnum_of_coupon#quantity of item required for coupon to workif((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 quantityapply_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_hashapply_coupons_hash[name]={:price=>attributes[:price],:clearance=>attributes[:clearance],:count=>attributes[:count]}endendapply_coupons_hashend
This monstrous piece of code is 28 lines long…
No way am I going to remember what each part does a week later.
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.
123456
cart.eachdo|item|item_hash={}item_hash[:name]=item_array.firstitem_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.
Now that we dumped that into it’s own method, our cart.each do looks a litle bit better.
12
cart.eachdo|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.
123456789
coupons.eachdo|coupon_hash|#get num and cost of that particular item from coupons hashifcoupon_hash[:item]==namenum_of_coupon=coupon_hash[:num]coupon_price=coupon_hash[:cost]endendnum_of_coupon#quantity of item required for coupon to workif((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.
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?” ?
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.
123456789101112131415161718
defapply_coupons(cart:[],coupons:[])apply_coupons_hash={}cart.eachdo|item|item_hash=build_item_hash(item)matching_coupon_for_item=coupons.detect{|coupon|coupon[:item]==item_hash[:name]}ifmatching_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}elseapply_coupons_hash[item_hash[:name]]={:price=>item_hash[:price],:clearance=>item_hash[:clearance],:count=>item_hash[:count]}endendapply_coupons_hashend# 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.
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.
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
Then, a new conversation will be started between you two. This means the message form will be nested inside the conversation form
Lastly, this will be the messaging app containing all your conversations, and you can see all the messages that belong to that particular conversation.
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.
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.
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
123456789101112131415
classConversation<ActiveRecord::Basebelongs_to:itembelongs_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 @conversationdefrecipient(current_user)if(current_user.id==self.user1_id)self.user2_idelse(current_user.id==self.user2_id)self.user1_idendendend
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.
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.
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.
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.
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.
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.
12345678910111213141516
<%= 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.
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.
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.
You don’t have to use up lots of storage space on your app.
Pulling images from the rails stack every time will make your app super slow.
After your free tier is over, you can get it for $0.03 per GB for the first 1 TB/month.
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 “ ”.
1234
# config/application.ymlamazon_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.
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.
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.
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
varusername=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
varusername=<%=ENV['geonames_username']%>
Then I tried to concatenate it into my API link to parse. WRONG
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.
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
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
123
functioncat(){prompt("Do you like cats?")};
Here is a function expression
123
varcat=function(){prompt("Doyoulikecats?)};
Ruby on the other hand, has three types of functions
blocks
procs
lambdas
Here is a block
1
[1,2,3].each{|x|putsx*2}
Here is a proc
12
p=Proc.new{|x|putsx*2}[1,2,3].each(&p)
Here is a lambda
12
lam=lambda{|x|putsx*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.
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.
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.
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.
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.
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.)
123456
# 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 arrayauthor.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:
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.
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.
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.