Combine API data with local data in Rails - ruby-on-rails-3

I am working with the GoCardless API in my Rails 3 application. I have a subscription model which has a resource_id column which matches the id of the remote record.
I am trying to get extra information for a local subscription record from the API.
Subscription Index View
<% #subscriptions.each do |subscription| %>
<tr>
<td><%= subscription.resource_id %></td>
<td><%= subscription.resource_type %></td>
<td><%= subscription.signature %></td>
<td><%= subscription.state %></td>
<td><%= #gocardless.next_interval_start %></td>
<td><%= link_to 'Show', subscription %></td>
<td><%= link_to 'Edit', edit_subscription_path(subscription) %></td>
<td><%= link_to 'Destroy', subscription, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
Subscription Controller
def index
#subscriptions = Subscription.all
#gocardless = GoCardless::Merchant.find("XXXXXXXXXX").subscriptions
respond_to do |format|
format.html # index.html.erb
format.json { render json: #subscriptions }
end
end
As you can see I'm using the following line to retrieve the next interval start date
<%= #gocardless.next_interval_start %>
This doesn't work and returns nil. However, if I change it to the following all records show the value from the first record from the API.
<%= #gocardless.first.next_interval_start %>
According to the GoCardless API documentation you can lookup a subscription using the following:
GoCardless::Subscription.find("XXXXXXXXXX") # => #<GoCardless::Subscription ...>
So, my question. How do I pass the current subscription resource_id to the API so that I can view the next_internal_start value for each of the local subscription records?
Update
Using Adam's example below I get a 404 response from GoCardless. I think it's due to me not setting the merchant ID in the request. When I change the method to:
def gc_subscription
#gc_subscription ||= GoCardless::Merchant.find("MERCHANTID").subscriptions.find(self.resource_id)
end
I get undefined methodinterval' for #` for any attribute I try and request using the following code:
<% for subscription in #subscriptions %>
<%= subscription.gc_subscription.amount
<% end %>
When using the same code to get local content it works as expected:
<% for subscription in #subscriptions %>
<%= subscription.resource_id %>
<% end %>
I've checked that the value I am trying to retrieve is available in the API. https://sandbox.gocardless.com/docs/api_guide#resources-available
Update Two
As before calling the first result works using Adam's method:
<%= subscription.gc_subscription.first.amount %>
This returns 2.5 which is the value of the first subscription.

If I had a local Subscription model which linked to a remote data source I would have a method like this on my Subscription model which provided access to the remote object:
def gc_subscription
#gc_subscription ||= GoCardless::Subscription.find(self.resource_id)
end
Then you can access this method as necessary without any need for any GC logic in the view or controller. For example:
for subscription in #subscriptions
subscription.gc_subscription.some_method #=> "output"
end
Or, if you are only working with one subscription:
subscription = Subscription.find(id)
subscription #=> Your local Subscription instance
subscription.gc_subscription #=> GoCardless::Subscription instance
With it configured like that, you will be able to remove the #gocardless from your controller and replace your view with this:
<% #subscriptions.each do |subscription| %>
<tr>
<td><%= subscription.resource_id %></td>
<td><%= subscription.resource_type %></td>
<td><%= subscription.signature %></td>
<td><%= subscription.state %></td>
<td><%= subscription.gc_subscription.next_interval_start %></td>
<td><%= link_to 'Show', subscription %></td>
<td><%= link_to 'Edit', edit_subscription_path(subscription) %></td>
<td><%= link_to 'Destroy', subscription, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
I hope that helps.

Related

Get sum of record attributes when grouping in Rails?

I am grouping mileage entries by month in my Rails 3.2 application:
mileages_controller.rb
def index
#mileages = Mileage.find_all_by_user_id(current_user.id)
#mileages_months = Mileage.find_all_by_user_id(current_user.id).group_by { |t| t.created_at.beginning_of_month }
respond_to do |format|
format.html # index.html.erb
format.json { render json: #mileages }
end
end
index.html.erb
<% #mileages_months.sort.each do |month, mileages| %>
<h4><%= month.strftime('%B %Y') %></h4>
<p>Total miles <strong><%= mileages.miles.sum %></strong>.</p>
<table>
<tr>
<th>Name</th>
<th>Miles</th>
<th>Start</th>
<th>Destination</th>
<th></th>
</tr>
<% for mileage in mileages %>
<tr>
<td><%= mileage.name %></td>
<td><%= mileage.miles %></td>
<td><%= mileage.start %></td>
<td><%= mileage.end %></td>
<td><%= link_to 'Show', mileage %></td>
</tr>
<% end %>
</table>
<% end %>
As you can see, I am trying to sum the total miles in each month using <%= mileages.miles.sum %>. This won't work - but <%= mileages.first.miles %> correctly shows the first entry's miles for each month.
What is the correct way of totalling up the miles column for each month?
Well you can create a helper method(to keep this logic seperate from the view) in the mileage_helper as :
def sum_mileges(mileages)
mileages.map(&:miles).sum
end
and then calling it in the view as
<p>Total miles <strong><%= sum_mileges(mileages) %></strong>.</p>
OR
you can do it directly as :
<p>Total miles <strong><%= mileages.map(&:miles).sum %></strong>.</p>

Tidiest way of highlighting record if older than X days?

What is the tidiest DRY way in a Rails 3 application of highlighting a table row depending on its age?
<% #faults_open.each do |fault| %>
<tr>
<td><%= fault.name %></td>
<td><%= fault.faulttype %></td>
<td><%= fault.priority %></td>
<td><%= time_ago_in_words(fault.created_at) %> ago</td>
<td><%= link_to 'Show', fault %></td>
</tr>
<% end %>
I would like a class applied to the table row with an indication of its age which I can then style using CSS.
<% #faults_open.each do |fault| %>
<tr <% if fault.created_at > Date.1.week.ago %>class="weekold"<% end %>>
<td><%= fault.name %></td>
<td><%= fault.faulttype %></td>
<td><%= fault.priority %></td>
<td><%= time_ago_in_words(fault.created_at) %> ago</td>
<td><%= link_to 'Show', fault %></td>
</tr>
<% end %>
Something like the above but obviously adding them to the view would be messy. I plan on adding a couple of ages, such as:
weekold
twoweeksold
monthold
sixmonthold
yearold
ancient
I imagine a helper is the tidiest way, but I'm unsure on how the helper would work. Any pointers would be appreciated.
I recently did something similar, adding a class name to the row that corresponded to it's approximate age in weeks, then I used CSS to do the actual highlighting.
Why not use a helper.. (just an example)
def highlight_age_class (created_at)
##today ||= Date.today
num_weeks = ((##today - created_at.to_date) / 7).floor
class_name = "aged_#{num_weeks}_weeks"
num_weeks == 1 ? class_name.singularize : class_name
end
With your HTML..
<tr class="<%= highlight_age_class fault.created_at %>">
Combined with some CSS..
.aged_1_week
.aged_1_weeks
.aged_4_weeks
.aged_24_weeks
.aged_56_weeks
etc
You can then focus on extending and optimizing your helper method for age highlighting.

What am I doing wrong with Rails has_many and belongs_to association?

I'm creating an app to log when files are moved to an archive drive, where they came from and were moved to and what user moved them.
This is my Archive model:
class Archive < ActiveRecord::Base
attr_accessible :archive_date, :start_dir, :end_dir, :user_id
#added by chris
belongs_to :user
end
This is my User model:
class User < ActiveRecord::Base
# new columns need to be added here to be writable through mass assignment
attr_accessible :username, :email, :password, :password_confirmation, :user_id
attr_accessor :password
before_save :prepare_password
before_save :assign_user_id
#added by chris
has_many :archives
def assign_user_id
self.user_id = User.maximum('user_id') + 1
end
end
This is my view:
<table id="archive_table">
<tr>
<th>Archive Date</th>
<th>Source Directory</th>
<th>Archive Directory</th>
<th>Archived By ID</th>
<th>Archived By Name</th>
</tr>
<% for archive in #archives %>
<tr>
<td><%= archive.archive_date %></td>
<td><%= archive.start_dir %></td>
<td><%= archive.end_dir %></td>
<td><%= archive.user_id %></td>
<td><%= archive.username %></td>
<td><%= link_to "Show", archive %></td>
<td><%= link_to "Edit", edit_archive_path(archive) %></td>
<td><%= link_to "Destroy", archive, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
</table>
<p><%= link_to "New Archive", new_archive_path %></p>
When I start up my local rails server via rails s Try to load the page. This is what I get:
NoMethodError in Archives#index
Showing c:/appname/app/views/archives/index.html.erb where line #21 raised:
undefined method `username' for #<Archive:0x203d750>
Extracted source (around line #21):
18: <td><%= archive.start_dir %></td>
19: <td><%= archive.end_dir %></td>
20: <td><%= archive.user_id %></td>
21: <td><%= archive.username %></td>
22: <td><%= link_to "Show", archive %></td>
23: <td><%= link_to "Edit", edit_archive_path(archive) %></td>
24: <td><%= link_to "Destroy", archive, :confirm => 'Are you sure?', :method => :delete %></td>
Rails.root: c:
Application Trace | Framework Trace | Full Trace
app/views/archives/index.html.erb:21:in `block in _app_views_archives_index_html_erb__238412483_16592988'
app/views/archives/index.html.erb:15:in `each'
app/views/archives/index.html.erb:15:in `_app_views_archives_index_html_erb__238412483_16592988'
Assuming the archive record is correctly saved with the users User_ID how do i get my view to display the name of the user via the has_many belongs_to association?
Thank You for looking at my question.
Archives have users, users have usernames--I think you're just up one level to "high"; use:
<%= archive.user.username %>

output belongs_and_has_many value in show action

I have the following code but can't render color as expected. When I render item.color I get #<Color:0x007ffce487a648>for example. If I render item.color.map(&:name) I get undefined method map for #<Color:0x007ffce6616918>
<% #this_week_orders.each do |order| %>
<tr style="font-weight:bold;">
<td><%= link_to "Order #{order.id}", order_path(order) %></td>
<td><%= l order.date, :format => :long %></td>
<td><%= pluralize(order.items.count, "item") %></td>
<td><%= number_to_currency(order.total_price) %></td>
<tr>
<% for item in order.items %>
<tr>
<td><li><%= item.product.name %></li></td>
<td><%= item.color %></td>
</tr>
<% end %>
<% end %>
Order has_many :items
Item belongs_to :order
Item belongs_to :product
Item belongs_to :color
scope :this_week, lambda { where("date > ?", 7.days.ago) }
Order controller
def this_week
#this_week_orders = Order.this_week.all
respond_to do |format|
format.html # index.html.erb
end
end
#<Color:0x007ffce487a648> reperesents an object of class Color (not a collection of color objects, whereupon it would make sense to use map). If Color has a name attribute, just write <%= item.color.name %>.
map is for use on an Array. item.color only returns one object. Use:
<%= item.color.name %>
if Color is a class like it appears to be you need to set the color value:
Something like:
<%= item.color.name %>
or whatever your value for the color is.

Rails calling a controller from another model's view

I have a post model and an upvote model.
upvote.rb
class Upvote < ActiveRecord::Base
has_one :user
belongs_to :post
end
# == Schema Information
#
# Table name: upvotes
#
# id :integer not null, primary key
# user_id :integer
# post_id :integer
# comment :text
# created_at :datetime
# updated_at :datetime
#
Now within posts/index I want to add an upvote for the current user and the post.
Some research pointed me to write a helper
posts_helper.rb
module PostsHelper
def upvote_post(post)
#upvote = Upvote.new
#upvote.user_id = current_user.id
#upvote.post_id = post.id
if #upvote.save
flash.now[:notice] = 'Upvote was successfully created.'
end
end
end
Inside my view I want to call the helper only on clicking a link but can't seem to get link_to working properly.
<% #posts.each do |post| %>
<tr>
<td><%= link_to "upboats" upvote_post(post) %></td>
<td><%= post.name %></td>
...
I get the error syntax error, unexpected tIDENTIFIER, expecting ')' and can't seem to find any good alternatives.
What am I missing here?
UPDATED
It was a comma. facepalm
Plenty of other issues, but that was what led to the error.
<% #posts.each do |post| %>
<tr>
<td><%= link_to "upboats", upvote_post(post) %></td>
<td><%= post.name %></td>
...
Closing open question.
It was a comma.
UPDATED
It was a comma. facepalm
Plenty of other issues, but that was what led to the error.
<% #posts.each do |post| %>
<tr>
<td><%= link_to "upboats", upvote_post(post) %></td>
<td><%= post.name %></td>
...