Blog

Ari
May 26, 2017
Ruby on Rails Tutorial No Comments

Rails Tutorial: Building Stock Market Application (2)

In the previous post, Rails Tutorial: Building Stock Market Application (part 1), we created authentication system, added bootstrap. In this post we are going to work on the Stock model, create the controller for it and add the ability to track stocks by the user. Let’s start by creating the stock model first. For this enter the following command in your terminal.

$ rails g model Stock ticker:string name:string last_price:decimal

This will create a Stock model with ticker( the symbol of stock eg APPL for Apple ), name( the name of company we are tracking the stock) and last_price attributes. So this generated the migration with all those properties. Let’s run the migration now.

$ rails db:migrate

Now the important part, we need some way to fetch the stock prices from the Yahoo API. For this we have a gem called stock_quote. This gem can go and lookup the stock price and all its details from a single query. So to add this gem add the following line in your Gemfile.

gem ‘stock_quote’

..

 

Now it’s time to run bundler. Run the following line

$ bundle install

This must successfully install the gem to your app. Now it’s time to play around with the gem and get to know how it works. Let’s hop into the rails console to see this.

$ rails console

This will open the interactive console for you. Now execute the following command to fetch the stock price of Facebook from the API.

>> StockQuote::Stock.quote(“FB”)

This must bring you ton of data related to Facebook stock. You can check the stock of Microsoft by MSFT and so on. If you want only the opening price and last close price, you can execute the following code.

>> StockQuote::Stock.quote(“symbol”).open

>> StockQuote::Stock.quote(“symbol”).previous_close

Now you get the idea, how we are going to get the data. We want to actually lookup the stock through front end part of our application though. For this we need to add some methods to our class. Open your stock.rb file from inside the models.Add the following code inside the class:

 

def self.find_by_ticker(ticker_symbol)

    where(ticker: ticker_symbol).first

end

 

def self.new_from_lookup(ticker_symbol)

   looked_up_stock = StockQuote::Stock.quote(ticker_symbol)

   return nil unless looked_up_stock.name

   new_stock = new(ticker: looked_up_stock.symbol, name: looked_up_stock.name)

   new_stock.last_price = new_stock.price

   new_stock

end

 

def price

 closing_price = StockQuote::Stock.quote(ticker).close

 return #{closing_price} (Closing)” if closing_price

 opening_price = StockQuote::Stock.quote(ticker).open

 return #{opening_price} (Opening)” if opening_price

 ‘Unavailable’

end

 

 

The methods are self explaining. We are added the self. prior to the method name, because these methods are not tied to any objects or object lifecycle, we need to be able to use them without having any instances of a stock.

Now let’s create a controller for the Stocks. Let’s give it a name StocksController and place the following code into it.

class StocksController < ApplicationController

 

  def search

    if params[:stock]

        @stock = Stock.find_by_ticker(params[:stock])

        @stock ||= Stock.new_from_lookup(params[:stock])

    end

 

    if @stock

        render partial: ‘lookup’

   else

        render status: :not_found, nothing: true

   end

end

end

 

 

Here, we create a simple controller with search method in it. The search method here searches the stock price from either database if the user has tracked the stock previously if not it will look through the API. So one thing to notice here is ||= operator. Most beginners get easily confused to it. Inside the if statement we have two statements, the first one calls the find_by_ticker method which is inside the stock.rb file we created earlier. That method takes the stock ticker as the parameter and returns the object if it is present in the database. Then, in the next line, ||= operator says that if the @stock object is present, leave it as it is. If not then assign it the value returned by the new _from_lookup function.

Now we need to create a route to search the stock. Open your config/routes.rb file and add the following line.

get ‘search_stocks’ => ‘stocks#search’

 

We don’t have a form for user to query the stock price yet. So create a partial called _lookup.html.erb. We are going to put our search code over there. Now fill the partial with the following code.

<div id=“stock-lookup”>

  <h3>Search for Stocks</h3>

  <%= form_tag search_stocks_path, remote: true, method: :get, id: ‘stock-lookup-form’ do %>

     <div class=“form-group row no-padding text-center col-md-12”>

        <div class=“col-md-10”>

             <%= text_field_tag :stock, params[:stock], placeholder:Stock Ticker Symbol‘, autofocus: true, class:form-control search-box input-lg‘ %>

        </div>

       <div class=“col-md-2”>

            <%= button_tag(type: :submit, class:btn btn-lg btn-success‘) do %>

                 <i class=‘fa fa-search’></i> Look up a stock

            <% end %>

       </div>

</div>

<% end %>

</div>

 

Text_field_tag is used in forms in rails if we want a simple form and it may not relate to database or like that. It is fancier to use this tag rather than plain html form tag. Now go to my_portfolio.html.erb and add the following line.

<%= render ‘stocks/lookup’ %>

Now, we want to display the @stock object into the browser. To do so we need to add some code into our template. In that lookup partial, add the following code just above the final div tag and below the <% end %> tag.

<% if @stock %>

   <div id=“stock-lookup-results” class=“well results-block”>

       <strong>Symbol:</strong> <%= @stock.ticker %>

       <strong>Name:</strong> <%= @stock.name %>

       <strong>Price:</strong> <%= @stock.price %>

  </div>

<% end %>

 

 

Ok most of the part of our app is working. Now we need to set up the ability of users to track the stock. To do so, we need to set up the association between them. A user can have many stocks and a stock can belong to many users. That means we have many to many relationship between them. To set up the many to many relationship, we create a different table called UserStocks. We need to create fields into it to make relationship. The table has field user_id and stock_id. Let do this first.

$ rails g model UserStock user_id:integer stock_id:integer

 

Now this must generate the migration file, we need to run the migration. Run the migration.

$ rails db:migrate

In the user model in user.rb file add the following lines so that they can actually set the relationship.

has_many :user_stocks

has_many :stocks, through: :user_stocks

 

 

Relationship should be defined in both directions so we can query from both side. For example we can query the database for stock given a user or query users that are tracking given the stock. So add the following lines in the stock.rb file too.

has_many :user_stocks

has_many :users, through: :user_stocks

 

In the userstocks model file add the following lines too.

belongs_to :user

belongs_to :stock

Now, next we need to add the tracking button in the front end of our app. Navigate to lookup partial and add the ability to add a stock to the user_stocks so they can be saved, add the following under the display of @stock.price (Price) within the <% if @stock %> branch:

<%= link_to “Add to my Stocks”, user_stocks_path(user: current_user, stock_ticker: @stock.ticker,stock_id: @stock.id ? @stock.id : ), class: ‘btn btnxs btnsuccess‘, method: :post %>

 

Now the final thing I want to do in this tutorial is create a userstocks controller and add the create action into it so new stocks with relationship with user can be created. Add the following code into the controller of userstocks.

def create

   if params[:stock_id].present?

           @user_stock = UserStock.new(stock_id: params[:stock_id], user: current_user)

   else

           stock = Stock.find_by_ticker(params[:stock_ticker])

   if stock

           @user_stock = UserStock.new(user: current_user, stock: stock)

   else

           stock = Stock.new_from_lookup(params[:stock_ticker])

  if stock.save

           @user_stock = UserStock.new(user: current_user, stock: stock)

  else

          @user_stock = nil

          flash[:error] = “Stock is not available”

   end

end

end

respond_to do |format|

   if @user_stock.save

       format.html { redirect_to my_portfolio_path, notice: “Stock #{@user_stock.stock.ticker} stock was successfully added” }

       format.json { render :show, status: :created, location: @user_stock }

   else

       format.html { render :new }

        format.json { render json: @user_stock.errors, status: :unprocessable_entity }

   end

end

end

 

 

Congratulations on getting this far on this ruby on rails tutorial. Now still there are limitless features you can add into the app. For example you can set up the friendship model and much more. You can use complex callbacks for filtering and searching.

The important step in building a rails app is setting up the relationships and controllers. If you have any confusion in doing so, you can always refer to the rails documentation.

Comment