Rails stock ticker dashboard widget proof of concept - ruby-on-rails

I’m new to rails and trying to expand beyond just the standard scaffolding. I would like to build a dashboard that isn’t based on just one model but a collection of models (partials?) to view weather, the stock market, etc. Some of this data will be pulled from queries from models. Other elements will be hard coded, like the stock ticker widget which I thought I would begin with.
I began by creating a dashboard.rb file in the lib folder. I used the following code
class Dashboard
def self.tickertable
yahoo_client = YahooFinance::Client.new
data = yahoo_client.quotes(["BVSP", "NATU3.SA", "USDJPY=X"], [:ask, :bid, :last_trade_date])
#ask = data.ask
end
end
Next, I added the necessary code to the application .rb file to load the lib folder
config.autoload_paths += %W(#{config.root}/lib)
I then added a _tickertable partial in a newly created views/shared folder.
<table>
<thead>
</thead>
<tbody>
<% Dashboard.tickertable.each do |ticker| %>
<tr>
<td><%= ticker.name %></td>
<td><%= ticker.symbol %></td>
<td><%= ticker.last_trade_price %></td>
</tr>
<% end %>
</tbody>
</table>
I put this partial to an already existing view which when it loads it gives the following error:
undefined method `ask' for #<Array:0x6663330>
on the "<% Dashboard.tickertable.each do |ticker| %>" line.
What key element am I missing? I feel like I am close but clearly something is missing.

Related

How to call a controller method in an associated view file?

I am trying to create a method in a controller file, and then call that method in the index.html.erb view file.
Here are both my index action and my custom method in the controller file:
def index
#mustdos = current_user.mustdos
end
def calculates_mustdos_days_left
((mustdo.created_at + 7.days - Time.now) / ( 60 * 60 * 24)).round
end
helper_method :calculates_mustdos_days_left
And here is the relevant code from my associated my index.html.erb file:
<% #mustdos.each do |mustdo| %>
<tr id="todo-<%= "#{mustdo.id}" %>">
<td><%= calculates_mustdos_days_left %></td>
</tr>
<% end %>
I am getting this error:
NameError in Mustdos#index
And it is referencing this line from my index.html.erb view file
<td><%= calculates_mustdos_days_left %></td>
How can I resolve this? Thanks.
In general, I try to leave my helper methods for when I need them to generate content/output for a view. When I want to calculate and return data regarding a particular Model instance, I either add that code to a Service or the model itself.
app/models/must_do.rb
def days_left
((self.created_at + 7.days - Time.now) / ( 60 * 60 * 24)).round
end
Then, in my view, it's easy to access this off the model's instance:
<% #mustdos.each do |mustdo| %>
<tr id="todo-<%= "#{mustdo.id}" %>">
<td><%= mustdo.days_left %></td>
</tr>
<% end %>
For me, this is a cleaner implementation of the desired behavior. Wanted to offer it as an alternative/additional approach to #IS04's answer.
you could try:
helper_method def calculates_mustdos_days_left(mustdo)
((mustdo.created_at + 7.days - Time.now) / ( 60 * 60 * 24)).round
end
and then in your view file:
<% #mustdos.each do |mustdo| %>
<tr id="todo-<%= "#{mustdo.id}" %>">
<td><%= calculates_mustdos_days_left(mustdo) %></td>
</tr>
<% end %>
but instead controller methods you should use helper methods, also if your method is more general (related to model) and doesn't depend from view, you could define it in your model as #craig.kaminsky written
You can't do it. You can't call methods outside of the controller action you are in in your view. If you have a piece of logic like that you should really try to get it into a model. In this case I would put this method in the mustdo model.
But in those cases where putting the logic into a model does not make sense you can use helper namespaces. It is sort of a miscellaneous drawer for methods that don't quite fit anywhere, like display logic. Helpers go in the app/helpers/ directory. By default there is a helper namespace file in there called application_helper.rb. Any method you put in there will be available in all your controllers and views.

Rails Scope, Helper Method?

I have three models. One is an Employee, one is an Item, and one is a Transaction that belongs to both Employee and Items. It's a simple app that allows Employees to check in and check out items - 'Transaction' has a boolean column for checked-in/checked-out.
What I'm trying to do is show within the employee/show view the current list of Items that an Employee has checked out. This is some rough code that I sketched out, but I'm not sure that it's going to work, and I was told not to use a lot of nested conditionals in my views anyway.
<% if #employee.transactions.exists? %>
<h3>Currently Checked-OUT Items</h3>
<table>
<tr>
<th>Item Asset Tag</th>
<th>Item Description</th>
</tr>
<% #employee.transactions.each do |transaction| %>
<% if item.transaction.last? && transaction.status == false %>
<tr>
<td><% transaction.assettag %></td>
<td><% transaction.description %></td>
</tr>
<% else %>
NO CHECKED OUT ITEMS
<% end %>
</table>
<% end %>
<% end %>
Basically, I'm trying to:
checks all employee transactions
compares the item involved in the transaction and sees if it's the .last transaction record for item
if it is, and if it's false, then it's a current checkout.
Is this a better job for a scope within the Transaction model, or a helper method? I've never used either, I'm really new at rails.
You should do a couple of things in here.
First - create a scope that will fetch last item transaction for you. There's no point in going through al item transactions if you're interested in the last one only, right?
Second, use partials. In this example it's hard to show how I would refactor code to use them (some things doesn't make sense here, ex. where does item variable come from?)
Scope example (take last transaction)
#item.transactions.order('created_at DESC').first
You can as well add scopes for checkin / checkout
class Transaction
scope :checkin, -> { where(status: true) }
scope :checkout, -> { where(status: false) }
end
First, you are on the right track. When views get ugly and hard to read because of extensive embedded ruby conditionals and such, think about moving the logic into a helper.
If you have a typical rails app, you'll already have app/helpers/application_helper.rb
So you could just create a helper in that file
def make_employee_list(employee)
if employee.transactions.exists?
content_tag(:div) do
content_tag(:h3, "Currently Checked-OUT Items")
content_tag(:table) do
employee.transactions.each do |transaction|
# you get the idea
end
end
end
end
end
Then in your view you could do this:
<%= make_employee_list(#employee) %>

How to call data from a table associated with a different controller

I'm kind of new to RoR so this may be a stupid question, but is there
any way to pull data associated with one controller into a form in the view of
another?
I have 2 controllers, home and subjects and I have one model subject (probably a poor choice in hindsight). I have a table in my database called subjects and a column in that table called text I want to pull data from that column into both my home and subjects views and i can do it fine in the subjects view but i can't get it to work in the home view.
I'm doing it with
def index
#subjects = Subject.order("subjects.position ASC")
end
in the subjects controller, and
<tr>
<th>Text</th>
<td><%= #subject.Text %></td>
</tr>
in the view.
Let me know if you need any more information, Thanks.
put this in your view
<% for subject in #subjects %>
<tr>
<th>Text</th>
<td><%= subject.text %></td>
</tr>
<% end %>
Note that I am using subject as opposed to #subject inside the loop, and that .text is not capitalised as in your code
Controllers are only associated to tables by convention.
Models are associated to tables, and you can use whatever models you want in your controllers.

Undefined Method, across classes, for a database derived field

I'm aware that variants of this question have been asked before, but I do believe my question is different ;-)
I have 2 Ruby on Rails classes (with assoc. controllers, models, etc). These are Devices and Messages.
In the Devices index.html view, I need to make reference to the newest Message record.
<table>
<tr>
<th>Device Name</th>
<th>Checked</th>
</tr>
<% newestMessage = Message.find(:all, :order => "updated_at DESC", :limit => 1) %>
<% #devices.each do |device| %>
<tr>
<td><%= device.name %></td>
<td><%= newestMessage.updated_at %></td>
</tr>
<% end %>
</table>
(I believe I should move the logic to a helper, but for the time being I'm keeping it as simple as possible while I get it working)
When I access this blahblah.com/devices, I get...
undefined method `updated_at' for #<Array:0x103f36c00>
Due to the line,
<td><%= newestMessage.updated_at %></td>
Now, I've seen questions like this that suggest to add the equivalent of the following to messages_controller.rb,
attr_accessor :updated_at
However, I've tried this and it doesn't help. Also, I don't think this should be necessary anyway as 'updated_at' is derived from the database, built with scaffold, etc.
If I just print 'newestMessage' it seems to have a sensible value.
My question is, how should I access fields within newestMessage, which are of class Message from the Device index.html.erb?
Thanks in advance.
Try newestMessage = Message.last then newestMessage.updated_at

Data Transfer Objects VS Domain/ActiveRecord Entities in the View in RoR

I'm coming from a .NET background, where it is a practice to not bind domain/entity models directly to the view in not-so-basic CRUD-ish applications where the view does not directly project entity fields as-is.
I'm wondering what's the practice in RoR, where the default persistence mechanism is ActiveRecord. I would assert that presentation-related info should not be leaked to the entities, not sure though if this is how real RoR heads would do it.
If DTOs/model per view is the approach, how will you do it in Rails?
Your thoughts?
EDIT:
Some examples:
- A view shows a list of invoices, with the number of unique items in one column.
- A list of credit card accounts, where possibly fraudulent transactions were executed. For that, the UI needs to show this row in red.
For both scenarios, The lists don't show all of the fields of the entities, just a few to show in the list (like invoice #, transaction date, name of the account, the amount of the transaction)
For the invoice example, The invoice entity doesn't have a field "No. of line items" mapped on it. The database has not been denormalized for perf reasons and it will be computed during query time using aggregate functions.
For the credit card accounts example, surely the card transaction entity doesn't have a "Show-in-red" or "IsFraudulent" invariant. Yes it may be a business rule, but for this example, that is a presentation concern, so I would like to keep it out of my domain model.
In general I would answer that your AcitveRecord object can contain any fields and you show in views only what you want. There is scaffolding task in rails scripts but it is only to create some setup model, controller and view. When I work with Rails I don't use ./script/generate scaffold at all. Rather I'm generating only model and controller separatly. The view part I add manualy.
ActiveRecord only maps data from database to some nice objects. What you do with it in view is up to you.
According to separation between presentation and business rules I think that fallowing examples would make it clear to you how to handle it in Rails.
For your invoice example I would create a view this way:
<h1>Invoices</h1>
<table>
<tr>
<th>Invoice #</th>
<th>Date</th>
<th>Name</th>
<th>No. of line items</th>
etc
</tr>
<% #invoices.each do |invoice| %>
<tr>
<td><%= invoice.number %></td>
<td><%= invoice.date.to_s %></td>
<td><%= invoice.name %></td>
<td><%= invoice.line_items.count %></td>
etc.
</tr>
<% end %>
</table>
Or even put a row with invoice data into separate partial and render it in above view. I assume that in your model you have:
# Invoice model
has_many :line_items
Now lets take a look on credit card example. I would do it like this:
# In CreditCard model add method
def fraudulent?
#put here some logic that returns true or false
end
Then in your view when you render this credit card:
<div <%= #credit_card.fraudulent? ? 'class="show_in_red"' : '' %>
here you can show whatever you want
</div>
Or even create helper for it:
# credit card helper
def add_show_in_red(credit_card)
credit_card.fraudulent? ? 'class="show_in_red"' : ''
end
# in Rails 3 or earlier version with plugin that puts `h` method by default
# your helper should have additional safe_html! call
def add_show_in_red(credit_card)
(credit_card.fraudulent? ? 'class="show_in_red"' : '').safe_html!
end
and in view:
<div <%= add_show_in_red(#credit_card) %>>
here you can show whatever you want
</div>

Resources