Loop through rails associations - ruby-on-rails

1)I'm trying to create a site that has several restaurants each having their own unique menu being displayed in a table, the association works in the console but not in code.I loop over the #restaurant instance variable then in the table I put the data I want from the menu so restaurant.menu.dish but getting an error that 'each' is undefined even though I didn't state a one-one relationship.How may I carry out the desired behavior?
2) How do I ensure that the menu data corresponds with the right restaurant,I'm assuming that the show controller saves the restaurant variable with a specific ID and calling a method like .dish would know what restaurant based on the show action variable, is this correct thinking?
Restaurant Model
class Restaurant < ActiveRecord::Base
has_attached_file :thumbnail, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment_content_type :thumbnail, content_type: /\Aimage\/.*\Z/
has_many :menus
def self.search(search)
if search
#restaurants= Restaurant.where("name LIKE ?", "%#{search}%")
else
#restaurants=Restaurant.all
end
end
end
Menu Model
class Menu < ActiveRecord::Base
belongs_to :restaurant
end
Restaurant controller with show action
def show
#restaurant = Restaurant.find(params[:id])
end
Show.html.erb
<div class="col-md-8">
<table class="table table-striped">
<h3>Menu</h3>
<thead><tr><th>Dish</th><th>Price</th><th>Calories</th></tr></thead>
<tbody>
<%= #restaurant.each do |restaurant| %>
<tr>
<td><%= restaurant.menu.dish %></td>
<td><%= restaurant.menu.price %></td>
<td><%= restaurant.menu.price %></td>
</tr>
<tr><td>..</td><td>..</td><td>..</td></tr>
<% end %>
</tbody>
</table>
</div>

You are showing restaurant, that has many menus, right? Here we go:
<%= #restaurant.menus.each do |menu| %>
<tr>
<td><%= menu.dish %></td>
<td><%= menu.price %></td>
</tr>
<tr><td>..</td><td>..</td><td>..</td></tr>
<% end %>

Related

How to use has_many fields in views, rails?

Frnds I am new to rails, here i created two tables caleed stocks and stock_availabilities.
in the stock model
class Stock < ActiveRecord::Base
belongs_to :projects_lkp
has_many :stock_availabilities
validates_presence_of :item
end
In the stock_availabilities model
class StockAvailability < ActiveRecord::Base
belongs_to :stock
validates_presence_of :qty,:add_or_issue,:price, :captured_at, :stock_id,:unit
end
Now my doubt is how to bring the field of stock_availabilties in the views of stock
<% #stock.each do |d| %>
<tr>
<td><%= d.item %></td>
"Here i need to print the values of qty and pricevwhich is in stock_availabilities class"?
</tr>
You are on the right track.
this is what you need:
<% #stock.each do |d| %>
<tr>
<td><%= d.item %></td>
<% d.stock_availabilities.each do |sAV| %>
<td> <%= sAV.qty %> </td>
... <-- You do the other ones here
<% end %>
</tr>

How do I get the table column data from one model into the view of another?

I want the customer name to appear in the customer name column on one of my model view pages, but I can't seem to figure out how to do this.
Here are my associations:
Customer Model is -
class Customer < ActiveRecord::Base
has_many :appointments, :dependent => :destroy, :as => :customer
has_many :birds, :dependent => :destroy, :as => :customer
end
Bird Model is -
class Bird < ActiveRecord::Base
belongs_to :customer
has_one :appointment
end
I've also added this to the Bird model index view -
<tbody>
<% #birds.each do |bird| %>
<tr data-link="<%= bird_path(bird) %>">
<td><%= bird.customer_id %></td>
<td><%= bird.name %></td>
<td><%= bird.breed %></td>
<td><%= bird.color %></td>
<td><%= bird.age %></td>
</tr>
<% end %>
The customer parameter I'd like to pass into the customer name column on the birds index view page is customer.name, or :name. If I try that, I get an undefined methods error on my /birds page.
Thanks!
I would expect that this should work:
<%= bird.customer.name %>
Or - if you have birds without an customer - you might want avoid exceptions like this:
<%= bird.customer.try(:name) %>
Or - less error prone - add the following to your bird model:
delegate :name, to: :customer, allow_nil: true, prefix: true
And use it in your views like this:
<%= bird.customer_name %>
You need to use in your view like this :
<%= bird.customer.name %>
In your controller, for the bird index page:
when you query for Bird.all, do Bird.all.includes(:customer)
then you will have access to <%= bird.customer.name %> in the view

Checking whether a user owns incoming and outgoing service booking requests

Use case: A user creates a service and can have many services. A user can book the service of another user through a servicebooking. A user can accept/decline the booking for their service from another user.
I am trying to display the outgoing service bookings made by the current user for another users services by checking a servicebookings model and also check/display the incoming bookings made by other users for the current users services on a myservicebookings page.
Myservicebookings view is as follows:
<h1>My Service bookings</h1>
<% if #owns_s %>
<table>
<tr>
<th><%= sortable "date" %></th>
<th><%= sortable "time" %></th>
<th><%= sortable "service name" %></th>
</tr>
<h4>Incoming requests:</h4>
<% #servicebookings.each do |servicebooking| %>
<tr>
<td><%= servicebooking.date %></td>
<td><%= servicebooking.time %></td>
<td><%= servicebooking.service_name %></td>
<td><%= link_to "View this booking", servicebooking_path(servicebooking) %></td>
</tr>
<% end %>
</table>
<%else%>
<%= "You have no incoming service booking requests"%>
<%end%>
<% if #owns_sb %>
<table>
<tr>
<th><%= sortable "date" %></th>
<th><%= sortable "time" %></th>
<th><%= sortable "service name" %></th>
</tr>
<h4>Outgoing requests:</h4>
<% #servicebookings.each do |servicebooking| %>
<tr>
<td><%= servicebooking.date %></td>
<td><%= servicebooking.time %></td>
<td><%= servicebooking.service_name %></td>
<td><%= link_to "View this booking", servicebooking_path(servicebooking) %></td>
</tr>
<% end %>
</table>
<%else%>
<%= "You have made no outgoing service booking requests"%>
<%end%>
<%= will_paginate #servicebookings %>
<%= link_to "Homepage", :controller => "welcome", :action => "index" %>
In my servicebookings controller I have the following to check whether a user owns a service or a servicebooking, currently it just returns all the services and servicebookings instead of displaying only the services created by the current user that another user has booking(incoming requests) and instead of displaying the services booked by the current user(outgoing requests). Can anyone give some tips here?? Thanks in advance guys, much appreciated.
def myservicebookings
#servicebookings = current_user.servicebookings.includes(:user).search(params[:search]).order(sort_column + " " + sort_direction).paginate(:per_page => 4, :page => params[:page])
owns_servicebooking = current_user.servicebookings.detect do |sb|
sb.user == current_user
end
owns_service = current_user.services.detect do |s|
s.user == current_user
end
#owns_sb = owns_servicebooking
#owns_s = owns_service
end
Servicebooking model:
class Servicebooking < ActiveRecord::Base
attr_accessible :service_id, :date, :time, :user_id, :service_name, :accept_booking
belongs_to :user
belongs_to :service
def self.search(search)
if search
where('name LIKE ?', "%#{search}%")
else
scoped
end
end
end
Services model:
class Service < ActiveRecord::Base
attr_accessible :avatar, :avatar2, :avatar3, :avatar4, :name, :date_available, :time_available, :description, :price, :size, :company_name, :company_details
has_attached_file :avatar, :default_url => "/images/:style/missing.png"
has_attached_file :avatar2, :default_url => "/images/:style/missing.png"
has_attached_file :avatar3, :default_url => "/images/:style/missing.png"
has_attached_file :avatar4, :default_url => "/images/:style/missing.png"
belongs_to :user
belongs_to :event
has_many :comments, dependent: :destroy
has_many :servicebookings
def self.search(search)
if search
where('name LIKE ?', "%#{search}%")
else
scoped
end
end
end
has_many :through
I think you'll benefit from the has_many :through association
Your ServiceBooking model seems to be a join model, which needs to reference booking_id and service_id
The way you've got the system set up currently is to pull directly from this model. I think you'll be better to use it in conjunction with your other models. You'll literally just have to adapt your code slightly to affect this change:
#app/models/Service.rb
Class Service < ActiveRecord::Base
belongs_to :user
has_many :service_bookings
has_many :bookings, :through => :service_bookings
end
#app/models/Booking.rb
Class Booking < ActiveRecord::Base
belongs_to :user
has_many :service_bookings
has_many :services, :through => :service_bookings
end
#app/models/ServiceBooking.rb
Class Service < ActiveRecord::Base
belongs_to :service
belongs_to :booking
end
This will allow you to pull the actual data from the relative models, rather than just relying on the ServiceBooking model
The beauty of this is that because you can add extra attributes to join models in Rails, you'll be able to include other fields, such as user_id, inbound and outbound
Your Code
I'd do it like this:
#config/routes.rb
resources :users do
resources :bookings
resources :services
end
#app/controllers/users_controller.rb
def index
user = User.find(params[:id])
#bookings = user.bookings
#services = user.services
end
#app/controllers/bookings_controller.rb
def index
user = User.find(params[:user_id])
#bookings = user.bookings
end
#app/controllers/services_controller.rb
def index
user = User.find(params[:user_id])
#services = user.services
end
This will allow you to display the actual bookings / services for each user (all the services / bookings on the user index page; all relative records on bookings and services index actions)
Validation
If you follow these ideas, validation becomes somewhat more methodical
You can either use a before_create function on your ServiceBooking model (to check if the object matches the user_id), or you could perform some controller-based validation to see if the user_id is consistent
I should also mention that checking ownership of booking or service moves to the other models with this (I.E service belongs_to :user)

Check whether a user owns a service

I have service and servicebooking models. I want to be able to check whether the current user owns a service and display the servicebookings that have been made for that users services.
I am trying to display this in a myservicebookings page.
This is the myservicebookings action in the servicebookings_controller, in the commented line Iam trying to check whether the current user is the owner of any of the servicebookings made or the owner of any of the services booked, I need to advise on how to go about this?
def myservicebookings
#servicebookings = current_user.services.servicebooking.find(params[:user_id])
#servicebookings = current_user.servicebookings.search(params[:search]).order(sort_column + " " + sort_direction).paginate(:per_page => 5, :page => params[:page])
end
This is the myservicebookings view, Iam trying to display both incoming/outgoing requests for services for the current user:
<h1>My Service bookings</h1>
<table>
<tr>
<th><%= sortable "date" %></th>
<th><%= sortable "time" %></th>
<th><%= sortable "service name" %></th>
</tr>
<% if #servicebookings.any? %>
<h4>Incoming requests:</h4>
<% #servicebookings.each do |servicebooking| %>
<tr>
<td><%= servicebooking.date %></td>
<td><%= servicebooking.time %></td>
<td><%= servicebooking.service_name %></td>
<td><%= link_to "View this booking", servicebooking_path(servicebooking) %></td>
</tr>
<% end %>
<h4>Outgoing requests:</h4>
<% #servicebookings.each do |servicebooking| %>
<tr>
<td><%= servicebooking.date %></td>
<td><%= servicebooking.time %></td>
<td><%= servicebooking.service_name %></td>
<td><%= link_to "View this booking", servicebooking_path(servicebooking) %></td>
</tr>
<% end %>
</table>
<%else%>
<%= "You have no incoming or outgoing service booking requests"%>
<%end%>
<%= will_paginate #servicebookings %>
<%= link_to "Homepage", :controller => "welcome", :action => "index" %>
Servicebooking model:
class Servicebooking < ActiveRecord::Base
attr_accessible :service_id, :date, :time, :user_id, :service_name, :accept_booking
belongs_to :user
belongs_to :service
def self.search(search)
if search
where('name LIKE ?', "%#{search}%")
else
scoped
end
end
end
Services model:
class Service < ActiveRecord::Base
attr_accessible :avatar, :avatar2, :avatar3, :avatar4, :name, :date_available, :time_available, :description, :price, :size, :company_name, :company_details
has_attached_file :avatar, :default_url => "/images/:style/missing.png"
has_attached_file :avatar2, :default_url => "/images/:style/missing.png"
has_attached_file :avatar3, :default_url => "/images/:style/missing.png"
has_attached_file :avatar4, :default_url => "/images/:style/missing.png"
belongs_to :user
belongs_to :event
has_many :comments, dependent: :destroy
has_many :servicebookings
def self.search(search)
if search
where('name LIKE ?', "%#{search}%")
else
scoped
end
end
end
Thanks guys, any help is appreciated.
You can do something like this in your controller. Assuming that there is a owner method on ServiceBooking and Service
def myservicebookings
#servicebookings = current_user.servicebookings.includes(:user).search(params[:search]).order(sort_column + " " + sort_direction).paginate(:per_page => 5, :page => params[:page])
owns_servicebooking = current_user.servicebookings.detect do |sb|
sb.user == current_user
end
owns_service = current_user.services.detect do |s|
s.user == current_user
end
#is_an_owner = owns_servicebooking and owns_service
end
detect returns an object if it matches the block and since it is ruby you can use it in a boolean expression to get what you want.
UPDATE: added controller method to the code example above. To use it in your view something like:
<% if #is_an_owner %>
<markup/>
<% end %>
I am pretty certain that this is not the best option in your case but I don't know enough about your stuff to suggest otherwise. It may be a start though. You may want to consider putting parts of this down to the model or into a helper method instead.

Struggling to get two models to have relations. And who suffers? The views

I've got an app that sets timed challenges for users. Each user is associated with one or more challenges. I've setup the models so they connect via a join table. That works fine, but I'm having problems on my view level. In the index view for the challenges, data from the challenge model and from the user model are displayed. But where the view should display the user's name, it's just displaying "User." If you click on "User", you are taken to the correct "show" page for that user. So the link works fine, but I can't get the user's name to appear. Instead, I'm just getting the class name to appear. Any idea why?
Here's the code for the view. The file directly below is is views/challenges/index.html.erb
<%- model_class = Challenge.new.class -%>
<h1><%=t '.title', :default => model_class.model_name.human.pluralize %></h1>
<table class="table table-striped">
<thead>
<tr>
<th><%= model_class.human_attribute_name(:date) %></th>
<th><%= model_class.human_attribute_name(:time) %></th>
<th><%= model_class.human_attribute_name(:rider) %></th>
<th><%=t '.actions', :default => t("helpers.actions") %></th>
</tr>
</thead>
<tbody>
<% #challenges.each do |challenge| %>
<tr>
<td><%= link_to challenge.date, challenge_path(challenge) %></td>
<td><%= link_to challenge.duration, challenge_path(challenge) %></td>
<td><%= link_to challenge.users.name, user_path(challenge) %></td>
</tr>
<% end %>
</tbody>
</table>
And here's the relevant models.
Challenge.rb
class Challenge < ActiveRecord::Base
attr_accessible :date, :duration, :user
has_many :user_challenges
has_many :users, :through => :user_challenges
validates_presence_of :date, :duration
def self.winner
Challenge.find(:first, :order => "duration desc")
end
end
User.rb
class User < ActiveRecord::Base
attr_accessible :name, :email
has_many :user_challenges
has_many :challenges, :through => :user_challenges
validates_presence_of :name, :email
validates_uniqueness_of :email
def self.find_or_create(name, email)
user = User.find_by_email(email)
if user.present?
user.challenge = challenge
user.save
else
User.create(:name => name, :email => email)
end
end
end
Join table, aka User_challenge.rb
class UserChallenge < ActiveRecord::Base
belongs_to :challenge
belongs_to :user
end
challenge.users is a collection and .name is a ruby method that gives you the name of the class:
ruby-1.9.2-head :002 > Object.name
=> "Object"
Call the attribute something else (username).
Also, user_path(challenge) doesn't really make sense when a Challenge can have_many :users (which users path should it be?).
I think the users list is empty, and that's why users.first.username is nil.
the user_path(challenge) 'seems' like its working, but its probably always taking you to the users/challenge_id path, which is not what you want.
most likely something isn't saving correctly for you. verify that your users lists are not empty. hop in the console and test out the saving and reloading of your data

Resources