Newbie to rails, I think i might be overlooking something very simple here, but I am displaying a table twice in a partial, not sure if it's to do with my associations.
Here is the Properties controller:
class PropertiesController < ApplicationController
before_filter
def index
#property= Property.all
end
def new
#property = current_user.property.build if signed_in?
end
def show
#property = current_user.property.paginate( params[:page])
end
Here is the Users Controllers:
class UsersController < ApplicationController
before_filter :authenticate_user!
def index
authorize! :index, #user, :message => 'Not authorized as an administrator.'
#users = User.all
end
def show
#user = User.find(params[:id])
#property = #user.property.paginate(page: params[:page])
end
Here are the associations in the models:
user model:
class User < ActiveRecord::Base
has_many :property, dependent: :destroy
property:
class Property < ActiveRecord::Base
attr_accessible :address, :name
belongs_to :user
Here is the _property.html.erb partial
<li>
<table>
<tr>
<th>Name</th>
<th>address</th>
</tr>
<% #user.property.each do |property| %>
<tr>
<td><%= property.name %></td>
<td><%= property.address %></td>
</tr>
<% end %>
</table>
</li>
Here is the show.html.erb
<div class="row">
<aside class="span4">
<section>
<h1>
My Properties
</h1>
</section>
</aside>
<div class="span8">
<% if #user.property.any? %>
<h3>Properties (<%= #user.property.count %>)</h3>
<ol>
<%= render #property %>
</ol>
<%= will_paginate #property %>
<% end %>
</div>
</div>
This is what is rendered in the browser. http://i.imgur.com/SlilDo3.png
Let me know if there is anything else will be of help with this question. All responses appreciated.
Where you do #property = Property.all you are setting up a collection of instances of the Property class... there's clearly more than on in this collection.
When you use
render #property
it will render the _property template for every item in the collection called #property
Even if, inside the _property template you then use user.property.each - then that means that you're effectively saying:
for each property in #property, render the template _property... and
each time you do that, render a new table that does a table row for
each property in user.property.
if you want only one table, and only each row to be rendered per individual "property" in the list of properties that is called #property then you need to pull the table outside of the render.
eg:
<h3>Properties (<%= #user.property.count %>)</h3>
<table>
<tr>
<th>Name</th>
<th>address</th>
</tr>
<%= render #property %>
</table>
and _property:
<tr>
<td><%= property.name %></td>
<td><%= property.address %></td>
</tr>
Related
I have an Order model, a LineItem model and a Product model. Below are the associations. I'm trying to figure out how to access the name attribute in the Product model. My first thought was to iterate over the LineItem table to gather the line_items where order_id == order that is used in the show view. Then, iterate over the new line_items and get each product name from the product_id attribute of the line_item. This would have to be done in a method, probably in the Order model. Is there a better way this can be done using Rails associations? My current implementation results in undefined method product for #Order:0x007f5d007305f0
order.rb
class Order < ApplicationRecord
has_many :line_items
belongs_to :user
accepts_nested_attributes_for :line_items
after_validation :set_amount
private
def set_amount
self.amount = line_items.map(&:product).map(&:cost).inject(:+)
end
end
product.rb
class Product < ApplicationRecord
has_many :line_items
end
line_item.rb
class LineItem < ApplicationRecord
belongs_to :order
belongs_to :product
end
order/show.html.erb
<h3>Customer - <%= #order.user.first_name %> <%= #order.user.last_name %></h3>
<h4>Order Date - <%= #order.created_at.to_s(:date_us) %></h4>
<%= #line_items.each do |item| %>
<table class="table">
<thead>
<tr>
<th>Product Quantity</th>
<th>Product Name</th>
<th class="text-right">Subtotal</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row"></th>
<td><%= item.order.product.name %></td>
<td class="text-right"></td>
</tr>
</tbody>
</table>
<% end %>
<div class="text-right">
<h3><%= #order.amount %></h3>
</div>
orders_controller.rb
class OrdersController < ApplicationController
before_action :authenticate_user!
def index
#orders = Order.all
end
def show
#order = Order.find(params[:id])
#line_items = LineItem.all
end
def new
#order = Order.new
#order.line_items.build
end
def create
#order = current_user.orders.build(order_params)
if #order.valid?
#order.save
redirect_to order_receipt_path(#order)
else
render :new
end
end
private
def order_params
params.require(:order).permit(line_items_attributes: [:id, :name, :product_id])
end
def products
#products ||= Product.all
end
helper_method :products
end
You receive the following error, because the Order model doesn't have project association, but the LineItem has.
You might want to filter the line items by order in the controller show method:
def show
#order = Order.find(params[:id])
#line_items = #order.line_items
end
And then iterate over them and display their project names:
<h3>Customer - <%= #order.user.first_name %> <%= #order.user.last_name %></h3>
<h4>Order Date - <%= #order.created_at.to_s(:date_us) %></h4>
<%= #line_items.each do |item| %>
<table class="table">
<thead>
<tr>
<th>Product Quantity</th>
<th>Product Name</th>
<th class="text-right">Subtotal</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row"></th>
<td><%= item.product.name %></td>
<td class="text-right"></td>
</tr>
</tbody>
</table>
<% end %>
<div class="text-right">
<h3><%= #order.amount %></h3>
</div>
Order doesn't know product. You should call item.product.name instead of item.order.product.name
Also consider eager loading products to avoiding N+1 query problem. You can do this in the OrdersController#show action with: #order.line_items.includes(:product)
I'm trying to show the avatar of each user who has commented in a topic. I pretty much have a Topic Model and a Comment Model. In my index page i have a list of all the topics created and a list of avatar of the user who commented but it only gets the list of the first topic and the images get repeated.
This is what i have in my index but I end up getting the avatar of each comment with repeated images.
<tbody>
<% #topics.each do |topic| %>
<th class="topic"> <%= link_to topic.title, topic %> </th>
<th class="category"><%= topic.category.title %></th>
<th class="users"><%= image_tag topic.user.avatar.url(:thumb)%></th>
<th class="replies"><%= topic.comments.count %> </th>
<th class="replies"></th>
<th class="activities"></th>
<% #comment.each do |comment| %>
<%= image_tag comment.user.avatar.url(:thumb) %>
<% end %>
<% end %>
</tbody>
My comments controller
class CommentsController < ApplicationController
def index
#topics = Topic.all
#comments = Comment.includes(:user)
end
def create
#comment = #commentable.comments.new(comment_params)
#comment.user_id = current_user.id
#comment.save
redirect_to #commentable
end
private
def comment_params
params.require(:comment).permit(:body)
end
end
You are displaying the user of only one comment.
<% #comment.each do |comment| %>
You probably need to get all comments of the topic instead. See below.
<% topic.comments.each do |comment| %>
To avoid N+1 issue, you can eager load the comments too
def index
#topics = Topic.includes(:comments => :user)
end
To display unique users, you can use Array#uniq with a block.
Assuming comments table has user_id, as foreign key,
<% topic.comments.uniq(&:user_id).each do |comment| %>
I'm new to Rails and I'm building a quizz application.
I have a has_many and belongs_to association set up between two models: Level and Question.
#models/level.rb
class Level < ActiveRecord::Base
has_many :questions
end
#models/question.rb
class Question < ActiveRecord::Base
belongs_to :level
attr_accessible :level_id
end
I have an action 'startlevel' in my LevelController that simply lists all the levels.
class LevelsController < ApplicationController
def startlevel
#levels = Level.all
end
and the view with links to go to the first question of the level. I want to add the id of the level as a parameter in the link. I noticed the 1 in the url of the view. I have no idea why how it came there and if it is part of my problem.
#controller/levels/startlevel/1
<h2>which level would you like to play</h2>
<table>
<tr>
<th>level</th>
</tr>
<% #levels.each do |level| %>
<tr>
<td> level <%=level.number %></td>
<td><%= link_to '<> play this level', :controller => "questions", :action => "answer",:level_id=> level.id%></td>
</tr>
<% end %>
</table>
When I follow the the link, I want to go to the first question with a level_id that matches the id parameter in the link_to, so i tried to do this:
class QuestionsController < ApplicationController
def answer
#question = Question.find_by_level_id(params[:level_id])
end
with this view
<p>
<b>Question:</b>
<%=h #question.word %>
</p>
<p>
<b>1:</b>
<%=h #question.ans1 %>
</p>
<p>
<b>2:</b>
<%=h #question.ans2 %>
</p>
<p>
<b>3:</b>
<%=h #question.ans3 %>
</p>
<p>
<b>4:</b>
<%=h #question.ans4 %>
</p>
<%= form_tag(:action => "check", :id => #question.id) do %>
<p>
<b>the correct answer is number: </b>
<%=text_field :ans, params[:ans]%>
</p>
<p><%= submit_tag("check")%></P>
<% end %>
unfortunately, whatever i tried, all i got for the last couple of hours was:
undefined method `word' for nil:NilClass
(word is an attribute of a question)
I want to cry. what am I doing wrong?
p.s. my idea is to add a link_to_unless in the 'answer'view which goes to the next question of the same level unless the next one is nil, so i think i need to group the questions with the same reference key somehow?
It works right now, however i'm not sure if this is the prettiest solution. Views/levels/play is empty since it only redirects to the first question of the level.
class LevelsController < ApplicationController
def startlevel
#levels = Level.all
end
def play
#level = Level.find(params[:id])
#question = Question.find_by_level_id(params[:id])
redirect_to controller: 'questions', action: 'answer', id: #question.id
end
#views/levels/startlevel
<h2>Which level would you like to play</h2>
<table>
<tr>
<th>level</th>
</tr>
<% #levels.each do |level| %>
<tr>
<td> level <%=level.number %></td>
<td>
<%= link_to '<> Play this level', :action => "play", :id=>level.id %></td>
</tr>
<% end %>
</table>
QuestionsController
class QuestionsController < ApplicationController
def answer
#question= Question.find(params[:id])
end
edit: Routes:
quizz::Application.routes.draw do
resources :questions
resources :levels
get "home/index"
root :to => 'home#index'
match ':controller/:action/:id', via: [:get, :post]
match ':controller/:action/:id.:format', via: [:get, :post]
I'm trying to develop a simple exercise log app, and I'm stuck (again). A user selects a category, and a specific workout, and I return a list of exercises belonging to that workout.
An effort is a user specific instance of an exercise.
class Exercise < ActiveRecord::Base
has_many :efforts
end
class Effort < ActiveRecord::Base
belongs_to :exercise
end
I'm retrieving the list of exercises in the efforts controller
class EffortsController < ApplicationController
def log_workout
#exercises = Exercise.where("category_id = ? AND workout_id = ?", params[:exercise][:category_id], params[:exercise][:workout_id])
#effort = Effort.new
end
end
The user logs their workout by using the following form
<%= form_tag save_workout_path, method: :put do %>
<table>
<tr>
<th>Exercise</th>
<th>Sets</th>
<th>Reps</th>
</tr>
<% #exercises.each do |exercise| %>
<%= fields_for "efforts[]", #effort do |f| %>
<tr>
<td><%= exercise.name %></td>
<td><%= f.number_field :sets %></td>
<td><%= f.number_field :reps %></td>
<%= f.hidden_field :exercise_id, :value => exercise.id %>
</tr>
<% end %>
<% end %>
</table>
<%= submit_tag "Log it" %>
<% end %>
class EffortsController < ApplicationController
def create
params[:efforts].each do |values|
if current_user.efforts.create(values)
flash[:notice] = 'Efforts were successfully saved.'
else
render action: 'new'
end
end
end
end
How right this is, I'm not sure, but it works. My problem now is trying to retrieve saved 'efforts' and allowing them to be modified through the same form. (Letting the user edit their workout log). Would appreciate any guidance/help
Hello i created 2 tables (categories and employees),both are in a relationship and i want to show category_name(Categories table) in my employees index view instead of id's
****Here is my Categories Table******
class CreateCategories < ActiveRecord::Migration
def self.up
create_table :categories do |t|
t.string :category_name
end
end
def self.down
drop_table :categories
end
end
****Here is my Enployees Table******
class CreateEmployees < ActiveRecord::Migration
def self.up
create_table :employees do |t|
t.string :name
t.string :last_name
t.integer :categories_id
end
execute "ALTER TABLE employees ADD CONSTRAINT fk_employees_categories FOREIGN KEY (categories_id) REFERENCES categories (id)"
end
def self.down
drop_table :employees
end
end
****Here is my Employee controller******
class EmployeeController < ApplicationController
def index
#employees = Employee.all
end
end
****Here is my Category controller******
class CategoryController < ApplicationController
def index
#categories = Category.all
end
end
****Here is my Category Model******
class Category < ActiveRecord::Base
has_many :employees
end
****Here is my Employee Model******
class Employee < ActiveRecord::Base
belongs_to :category
end
****Here is Employee view*******
<table>
<tr>
<th>Employee</th>
<th>Last Name</th>
<th>Category</th>
</tr>
<% #employees.each do |e| %>
<tr>
<td><%=h e.name %></td>
<td><%=h e.last_name %></td>
<td><%=h e.categories_id %>
</td>
Here in e.categories_id i want to show categories_name that is from my categories table
<td>
<%= link_to ("View" ,:controller=>"employee",:action=>"show", :id=>e.id ) %>
</td>
<td>
<%= link_to ("Edit", :controller=>"employee",:action=>"edit",:id=>e.id ) %>
</td>
<td>
<%= link_to ( "Delete",:controller=>"employee",:action=>"destroy", :id=>e.id ,:confirm=>"sure?" %>
</td>
</tr>
<% end %>
</table>
Can someone help me with this problem please?
In your employee index views,
<td><%=employee.categories.category_name %>
instead of
<td><%=h e.categories_id %>
<%= h e.category.category_name %>
will do the trick.
Note that if you just do this, it will cause an SQL query to be executed for each row that you're displaying (known as the N+1 problem).
So in your controller, you'll have to change
#employees = Employee.all
to
#employees = Employee.find(:all, :include => [:category])
This will force eager loading, and reduce the number of queries to 2.
(As a side note, you really should have moved on to Rails 3 by now. Rails 4 is current. Each version offers a lot more features than the last.)
In Your employee controller add this
It means that get category_name to appear on your index view instead of ID.
#category= Category.all()
#category_list=[]
#category.each do |c|
#category_list << [c.category_name,c.id]
end
and then in your index views
<td><%=employee.categories.category_name %>
I know this is a late answer, but for anyone who is looking for an answer, here is how I accomplished this,
I have a table realties that has a one to many association with features table. I used the railscast method for multiple checkbox selection, so for each realty it has certain features. I wanted to show the features of each realty in its row in the index view. I had in the show view, features are shown like this,
#realty.feature_ids
where #realty in the controller is
#realty = Realty.find(params[:id])
however, in the index view the realty.feature_ids only showed numbers only not the names.
To work this out here is what I did in the index view:
<% #realties.each do |realty| %>
<td>
<% realty.feature_ids.each do |feature| %>
<%= Feature.find(feature).name %>
<% end %>
</td>
<% end %>
so for the above question, loop through the ids with each loop, this will give you the id number, find it in the Category model with the .name method. So I guess the solution for you would look like this:
<% #employees.each do |employee| %>
<td>
<% employee.category_ids.each do |category| %>
<%= Category.find(category).name %>
<% end %>
</td>
<% end %>
I hope this will benefit someone.