Rails calling a controller from another model's view - ruby-on-rails-3

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>
...

Related

Combine API data with local data in Rails

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.

Associations in Rails 3

I have an app which allows users to add recipes and then select their favourite recipes to view in their member area, I can select a favourite and i am getting the user_id, recipe_id and giving it a favourite_id.
What I would like to do is output the actual recipe to my view (as a favourite), like dish name, country_of_origin etc. I can do this with an actual recipe but not the favourite.Do i need to use has_many_through for this?
My models look like this
User
has_many :recipes
has_many :favourites
recipe
belongs_to :user
has_many :ingredients
has_many :preperations
has_many :favourites
favourites
belongs_to :user
belongs_to :recipe
attr_accessible :user_id, :recipe_id
My controller
#favourites = current_user.favourites
my link_to post
<%= link_to "Add to favorites", {:controller => 'favourites', :action => 'create', :recipe_id => r.id}, {:method => :post } %>
i can list the current users recipes, this is my contoller for this
#recipes = current_user.recipes if current_user.recipes
and then output them to the view like so
<% #recipes.each do |r| %>
<tr>
<td><%= r.dish_name %></td>
<td><%= r.country_of_origin %></td>
<td><%= r.difficulty %></td>
<td><%= r.preperation_time %></td>
<td><%= ingredient_names(r.ingredients) %></td>
<td><%= preperation_steps(r.preperations) %></td>
<td><%= image_tag r.avatar.url(:thumb)%></td>
<tr>
So if i do this in the view
<li><%= #favourites %></li>
I get this outputted
<Favourite id: 16, user_id: 8, recipe_id: 21, created_at: "2012-11-07 20:24:39", updated_at: "2012-11-07 20:24:39">]
If i try
<%= #favourites.dish_name %>
then i get the error undefined method dish_name
How do i get the params of the recipe model to show in the view. I do apologise just cant work it out, which should be really easy i guess?
Any help appreciated
You get undefined dish_name because your Favourite model does not have such attribute.
#favourites = current_user.favourites returns an array of Favourite objects.
In your view you would do something like
<% #favourites.each do |f| %>
<%= f.recipe %>
<% end %>
That will display all the recipes your current_user favorites. You could narrow it down to display a specific recipe or what not.
The favorites is just holding the relationship.
You can access the recipe by
#favourites.recipe
which will then be a recipe object and contain your attributes like dish_name etc.
#favourites is an array, yes? Then you must loop through #favourites and work with each element individually as so:
<% #favourites.each do |favorite| %>
<%= favorite.recipe.dish_name %>
<% end %>

Simple associations with a legacy database in Rails 3?

I am working with a legacy database and am also reading through the Rails guides on associations.
I have two models. A diary model and an animal model.
diary.rb
class Diary < ActiveRecord::Base
establish_connection :premvet
attr_accessible :DiaryNo ,:DiaryName, :DiaryDate, :SlotHour, :TotalSlots, :BlockSlots, :BlockBooked, :FreeSlot, :BookedSlot
self.table_name = 'diary'
self.primary_key = 'DiaryNo'
has_many :animals, :foreign_key => 'DiaryQueue'
end
animal.rb
class Animal < ActiveRecord::Base
establish_connection :premvet
self.table_name = 'animal'
self.primary_key = 'PVID'
attr_accessible :AddedBy, :Age, :AnimalBFAmount, :AnimalBalance, :AnimalName, :Archive, :BillType, :Breed, :ChronicStatus, :Class, :Classification, :ClientKey, :Colour, :Date1, :DateOfBirth, :DateofBirth, :Dead, :DiaryQueue, :DiscField, :DrugsAtCost, :DrugsNoVAT, :ESDAmount, :ESDType, :FNote, :FirstRegisteredDate, :Height, :IDNumber, :Insured, :InsuredWith, :IsClient, :IsClientDate, :IsMaster, :LastBilledAmount, :LastBilledDate, :LastConsDate, :LastContributionDate, :LastPaidDate, :LastWeightDate, :Locked, :LoyaltyMultiplier, :LoyaltyPoints, :MR_Flag_0, :MR_Flag_1, :MR_Flag_10, :MR_Flag_11, :MR_Flag_12, :MR_Flag_13, :MR_Flag_14, :MR_Flag_15, :MR_Flag_2, :MR_Flag_3, :MR_Flag_4, :MR_Flag_5, :MR_Flag_6, :MR_Flag_7, :MR_Flag_7, :MR_Flag_8, :MR_Flag_9, :Mileage, :Neutered, :NextApptDate, :ORT, :OldSex, :Opt_Flag_0, :Opt_Flag_1, :Opt_Flag_2, :Opt_Flag_3, :Opt_Flag_4, :Opt_Flag_5, :Opt_Flag_6, :Opt_Flag_7, :PVID, :PreferredContact, :PreferredUser, :Ref1, :RefPrac, :ReferredBy, :SSDType, :SeenInPeriod, :SendBill, :Sex, :SiteAnimal, :Species, :Status, :SurcAmount, :SurcType, :SurgeryNumber, :TBU, :TOSAmount, :TOSDrugs, :TOSFees, :TOSType, :Weight
belongs_to :client, :foreign_key => 'ClientKey'
belongs_to :diary, :foreign_key => 'DiaryNo'
end
animals index view
<% #animals_todaysappointments.each do |animal| %>
<tr>
<td><%= animal.id %></td>
<td><%= animal.AnimalName %></td>
<td><%= link_to animal.client.Surname, animal.client %></td>
<td><%= animal.Species %></td>
<td><%= animal.Breed %></td>
<td><%= animal.NextApptDate.strftime("%d %b. %Y - %H:%M") %></td>
<td><%= animal.DiaryQueue %>
<td><%= animal.diary.DiaryName %></td>
<td><%= link_to 'Show', animal %></td>
</tr>
<% end %>
As you can see it's showing the DiaryQueue from the animal table using:
<td><%= animal.DiaryQueue %>
and I am trying to show the DiaryName from the diary table with:
<td><%= animal.diary.DiaryName %></td>
This fails with an exception error:
undefined method `DiaryName' for nil:NilClass
The #animals_todaysappointments method looks like this:
def appointments
#animals_todaysappointments = Animal.where('DATE(NextApptDate) = ?', Date.today).page(params[:page]).per_page(15).order('NextApptDate ASC')
respond_to do |format|
format.html # index.html.erb
end
end
If I add:
delegate :DiaryName, :to => :diary
to the animal model then I get the following error:
Animal#DiaryName delegated to diary.DiaryName, but diary is nil: #
Each animal record has a DiaryQueue value between 0 and 10 and the diary table has a number of rows, an example row is:
DiaryNo DiaryName DiaryDate SlotHour TotalSlots BlockBooked FreeSlot BookedSlot
--------------------------------------------------------------------------------------
1 Morning 2012-07-16 9 18 0 0 18
There are rows with the same DiaryNo, but they also have the same DiaryName. It's only the DiaryDate, SlotHour, TotalSlots, BlockBooked, FreeSlot and BookedSlot that alter in those rows.
To try and prevent the error I added the following to the view:
<% unless animal.DiaryName.nil? %>
<td><%= animal.DiaryName %></td>
<% else %>
<td><%= animal.DiaryQueue %>
<% end %>
but I get an exception:
Animal#DiaryName delegated to diary.DiaryName, but diary is nil: #
What am I doing wrong?
Given your answers above, you might need to change the belongs_to method in Animal to the following:
belongs_to :diary, :foreign_key => "DiaryQueue", :primary_key => "DiaryNo"
In your current implementation your models are going to try to match Animal#DiaryNo against Diary#DiaryNo, when what you've said you wanted is to match Animal#DiaryQueue against Diary#DiaryNo.

Rails 3: Join results in a view

Again I'm faced with something that should not on the face of it be this difficult but has been driving me mad for an hour or so. I have multiple models which I want to pull into one 'index' view. I assume it's a join but I can't seem to find a way to do it.
What I have in my index view:
<% #tips.each do |tip| %>
<tr>
<td><%= tip.user_id %></td>
<td><%= tip.city_id # here I want to draw on the cities table to show city.name
%></td>
<td><%= tip.type_id # here I want to draw on the type table to show type.name
%></td>
<td><%= tip.place_id # here I want to draw on the place table to show place.name
%></td>
<td><%= tip.tip_desc %></td>
<td><%= link_to 'Show', tip %></td>
<td><%= link_to 'Edit', edit_tip_path(tip) %></td>
<td><%= link_to 'Destroy', tip, confirm: 'Are you sure?', method: :delete %></td>
</tr>
<% end %>
Here are the models:
class Tip < ActiveRecord::Base
belongs_to :user
belongs_to :city
belongs_to :place
end
class Place < ActiveRecord::Base
belongs_to :city
has_and_belongs_to_many :collections
has_many :tips
end
class City < ActiveRecord::Base
has_many :places
has_many :tips
end
Any help will be really appreciated!
Thanks in advance,
James
Suggestions from other guys should work. I'm not sure, but it seems like you don't have objects within specified IDs in your database. That's all :)
Example:
#tips.each do |tip|
tip.city_id # 1
City.find( tip.city_id ) # nil
end

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.