I am new to the Rails framework and tried very long to fix this problem...
I want to display the team name a certain user belongs to, which works for the show action (user details), but not for the index action (all users)
I've created tables:
teams users
----------- ---------------
id (integer) id(integer)
name (string) fname(string)
lname(string)
team_id(integer)
I have the following classes:
class Team < ActiveRecord::Base class User < ActiveRecord::Base
attr_accessible :name, :user_id attr_accessible :fname, :lname, :team_id
has_many :users belongs_to :team
Then I have the following User controller:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def index
#users = User.paginate(page: params[:page], per_page: 15)
end
..and the code to display the user's team name is
Team: <%= #user.team[:name] %>
... which works perfectly fine... however, when I try to use the same code in the index view, like this, I get an error "undefined method `team' for nil:NilClass".
<table class="table table-striped">
<% #users.each do |user| %>
<tr>
<td>
<%= "#{user.fname} #{user.lname}" %>
</td>
<td>
Team: <%= #user.team[:name] %>
</td>
</tr>
<% end %>
</table>
What did I do wrong? Thanks for your help, I'd really appreciate it!
You're inside a block.
Instead of doing
Team: <%= #user.team[:name]
You should write
Team <%= user.team[:name]
Easy bug to overlook :)
Related
three-months-in beginner with Ruby on Rails here, so I apologize if any of my terminology is incorrect. I have a question about referencing outside models from a nested attribute.
I have three models. Tasks with nested attributes for Task Products, and a separate Items table with pre-populated products.
Each Task has many Task Products, and the Task Product has a "product_id" column which is in reference to an existing product in the Item table. In creating an table index of each Task, I am having trouble figuring out how to have the nested Task Product's product_id's list out the Item instead of just the bare id.
Here's the code I'm working with:
tasks_controller.rb -->
def dashboard
#tasks = Task.includes(:task_products, :storeorder).last(100)
#tasks.each do |task|
task.storeorder do |storeorder|
end
task.task_products.each do |task_product|
#item = Item.where(:id => task_product.product_id)
end
end
end
task.rb -->
class Task < ApplicationRecord
has_many :task_products
accepts_nested_attributes_for :task_products
end
task_product.rb -->
class TaskProduct < ApplicationRecord
belongs_to :task
has_many :items
end
item.rb -->
class Item < ActiveRecord::Base
belongs_to :task_product
def item_select
"#{vendor_name} (#{description})"
end
end
dashboard.html.erb -->
<td>
<% t.task_products.each do |tp| %>
# Existing code that lists each task product in a list on the table:
<p><%= tp.product_id %></p>
# The ideal code I would like to run:
<p><%= link_to #item.item_select, item_path(id: #item.id) %>
<% end %>
</td>
Any ideas how I can run the #item call as it pertains to the 'tp.product_id' code in the html file?
Appreciate any help I can get. Searching for this issue has left me with many purple links, but none of which address this particular issue.
EDIT: In case anybody happens upon this that was in the same predicament as me, I have one recommendation: Learn your associations.
Updated code:
tasks_controller.rb -->
def dashboard
#tasks = Task.includes(:task_products, :storeorder).last(100)
end
task.rb -->
class Task < ApplicationRecord
has_many :task_products
accepts_nested_attributes_for :task_products
end
task_product.rb -->
class TaskProduct < ApplicationRecord
belongs_to :task
belongs_to :item, foreign_key: :product_id
end
item.rb -->
class Item < ActiveRecord::Base
has_many :task_products, foreign_key: :product_id
def item_select
"#{vendor_name} (#{description})"
end
end
dashboard.html.erb -->
<td>
<% t.task_products.each do |tp| %>
<% tp.items.each do |item| %>
<p><%= link_to item.item_select, item_path(item) %></p>
<% end %>
<% end %>
</td>
First, by using Item.where in your controller, you're actually setting #item to a collection of Items. Second, by setting it inside a loop, you're overwriting it with each TaskProduct, so only the last one will be accurate in the view.
I'm assuming you want to list [a subset of] every Item for every Task. In that case, you'd be better not to set them in your controller at all:
def dashboard
#tasks = Task.includes(:task_products, :storeorder).last(100)
end
Instead, just loop through them in the view:
<% #tasks.each do |t| %>
Task <%= t %>
<% t.task_products.each do |tp| %>
TaskProduct <%= tp %>
<% tp.items.each do |item| %>
<p><%= link_to item.item_select, item_path(item) %></p>
<% end %>
<% end %>
<% end %>
I don't see any need of all the loops in your dashboard_controller.rb
#tasks.each do |task|
task.storeorder do |storeorder|
end
task.task_products.each do |task_product|
#item = Item.where(:id => task_product.product_id)
end
end
Here's what you need in html.erb:
# The ideal code I would like to run:
<% tp.items.each do |item| %>
<p><%= link_to item.item_select, item_path(item) %>
<% end %>
I am connecting to an external database with rails. I have an opportunities table that has a field
If I use the following code, I get the company name.
<% company_id = opportunity.Oppo_PrimaryCompanyId %>
<% #company = CrmTable::Company.where("Comp_CompanyId = ?", company_id) %>
<% #company.each do |company|%>
<td>
<%= company.Comp_Name %>
</td>
<% end %>
However, based on what I have done with associations with Rails databases, I thought I could do
<% company_id = opportunity.Oppo_PrimaryCompanyId %>
<% #company = CrmTable::Company.where("Comp_CompanyId = ?", company_id) %>
<%= #company.Comp_Name %>
When I try that, I get an error of
NoMethodError in Searches#show
Showing C:/Users/cmendla/RubymineProjects/product_development/app/views/shared/_opportunity_list.html.erb where line #56 raised:
undefined method `Comp_Name' for #<Company::ActiveRecord_Relation:0xa734738>
Trace of template inclusion: app/views/searches/show.html.erb
Rails.root: C:/Users/cmendla/RubymineProjects/product_development
Application Trace | Framework Trace | Full Trace
app/views/shared/_opportunity_list.html.erb:56:in `block in _app_views_shared__opportunity_list_html_erb__1021919415_87714420'
app/views/shared/_opportunity_list.html.erb:29:in `each'
app/views/shared/_opportunity_list.html.erb:29:in `_app_views_shared__opportunity_list_html_erb__1021919415_87714420'
app/views/searches/show.html.erb:16:in `_app_views_searches_show_html_erb__1026643635_104558460'
Request
Parameters:
{"id"=>"180"}
If I do a #company.inspect, I see the following for the id corresponding to the current opportunity
#<ActiveRecord::Relation [#<Company Comp_CompanyId: 7, Comp_PrimaryPersonId: 7, Comp_PrimaryAddressId: 13, Comp_PrimaryUserId: 35, Comp_Name: "XXX CORPORATION", Comp_Type: "Customer", Comp_Status: "Active", . . .
If I do Company Last<%= #current_company.last %>, I get Company Last#<Company:0x9103c50>
CrmTable.rb contains
class Opportunity < CrmTable
self.table_name = "Opportunity"
belongs_to :users, class_name: 'CrmUser', foreign_key: :Oppo_AssignedUserId
belongs_to :person, class_name: 'Person', foreign_key: :Oppo_PrimaryPersonId
belongs_to :company, class_name: 'Company', foreign_key: :Oppo_PrimaryCompanyId
end
class Company < CrmTable
self.table_name = "Company"
has_many :opportunities
alias_attribute 'company_name','Comp_Name'
end
Again, I can't understand why I have to walk through the company records vice using opportunity.company.Comp_Name
I'm not sure if the capitalization is causing a problem. However that is the result of the way the external table is designed.
<% #company = CrmTable::Company.where("Comp_CompanyId = ?", company_id) %>
returns a collection(Array of CrmTable::Company). If you want to call Comp_name on each item you can do
#company.map(&:Comp_name)
but obviously you would want to rename the variable to companies and move forward accordingly.
<% #company.each do |company|%>
<td>
<%= company.Comp_Name %>
</td>
<% end %>
Here #company is the array of the company objects. If you are expecting object then you should use first on the #company. it will return an object.
<% #company = CrmTable::Company.where("Comp_CompanyId = ?", company_id).first %>
Or
<% #company = CrmTable::Company.find_by_Comp_CompanyId(company_id) %>
<% if #company %>
<%= #company.Comp_Name %>
<% end %>
Model
class Register < ActiveRecord::Base
attr_accessor :code
belongs_to :user
end
class User < ActiveRecord::Base
has_many :register
end
Controller
def index
#registers = Register.all
end
View
<p> All Registers </p>
<table>
<tr>
<td> User </td>
<td> Point </td>
</tr>
<% #registers.each do |u| %>
<tr>
<td> <%= u.user.name %> </td>
<td> <%= u.hour %> </td>
</tr>
<% end %>
</table>
it onlys display Name instead of the field value
and the console is giving me this error
no such column: users.register_id: SELECT "users".* FROM "users" WHERE "users"."register_id" = ? LIMIT 1
First Add user_id to registers table.
Update your index action to below.
def index
#registers = Register.all
end
and view code to following.
<% #registers.each do |u| %>
<%= u.user.name %>
<%= u.hour %>
<% end %>
Update you user model to below.
class User < ActiveRecord::Base
has_many :registers
end
To add to #Dheeresha's great answer, you need to also appreciate that you actually have to associate the two objects. To do this, you can use the following (as a test):
$ rails c
$ user = User.first
$ register = Register.first
$ user.registers << register
This will ensure you have at least one register in the user.registers collection. The way to ensure this is not an issue in production / view is to use the .try method:
<% #registers.each do |u| %>
<%= u.user.try(:name) %>
<%= u.hour %>
<% end %>
The only reason you wouldn't be able to access the user object would be that it's not associated in ActiveRecord. This issue in itself could be caused by not having the associations defined correctly (as #Dheeresha pointed out), or not associating the objects (as I've mentioned).
--
Your models should look like:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :registers
end
#app/models/register.rb
class Register < ActiveRecord::Base
belongs_to :user
end
I have two tables - positions table with the fields id, position_id, first_name and last_name. The other table is positionslist with the fields id, positions.How will i able to join that two tables?
Here's my positionscontroller:
class PositionsController < ApplicationController
def index
##positions = Position.all(:order=>'updated_at DESC')
#positions = Position.joins(:positions => :positionlists)
end
def new
#position = Position.new
end
def create
#position = Position.new(params.require(:position).permit(:position_id, :first_name, :last_name))
if #position.save
redirect_to(:controller=>'positions')
else
render 'new'
end
end
def edit
#position = Position.find(params[:id])
end
def update
#position = Position.find(params[:id])
if #position.update(params.require(:position).permit(:position_id, :first_name, :last_name))
redirect_to(:controller=>'positions')
else
render 'edit'
end
end
def destroy
#position = Position.find(params[:id])
#position.destroy
redirect_to(:controller=>'positions')
end
end
my models position.rb
class Position < ActiveRecord::Base
has_many :positionlists
has_many :positionlists , :through => :positions
validates :first_name, length: { in: 4..20}
validates :last_name, length: { in: 4..20}
end
my models positionlists.rb
class Positionlists < ActiveRecord::Base
has_many :positions
end
any my postions index.html.erb
<% content_for :title, "Positions" %>
<%= render "layouts/nav" %>
<div class="clear"></div>
<h1>Positions List</h1>
<%= link_to "Add", new_position_path, :class =>'btn btn-success' %>
<br />
<br />
<table class="table">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Position</th>
<th>Options</th>
</tr>
<% #positions.each do |positions| %>
<tr>
<td><%= positions.first_name %></td>
<td><%= positions.last_name %></td>
<td><%= positions.position_id %></td>
<td>
<%= link_to "Edit", edit_position_path(positions)%> |
<%= link_to "Delete", position_path(positions),
method: :delete, data:{confirm: 'Are you sure you want to delete this?.' }%>
</td>
</tr>
<% end %>
</table>
any help is greatly appreciated! thanks
Rails takes care of this for you.
class PositionList < ActiveRecord::Base
has_many :positions
end
class Position < ActiveRecrod::Base
belongs_to :position_list
end
Also your position needs a position_list_id column for simplicity. If I'm understanding what you are trying to do here.
Other problems: naming your class PositionLists and not PositionList will confuse Rails automagic naming conventions.
Also you have an odd set of columns in your tables. For what you want as far as I can tell your positions table needs to have the columns:
first_name
last_name
id (automatic)
You don't appear to have anything in your position_list table so there's no column you need there outside of the automatic id column. The association is automatic from the belongs_to in the Position class and the position_list_id column in the positions table.
If you want to get an idea of how simple this all can be try running an automatic scaffolding, looking at how it's done there, and learning from that. Maybe a generate a fresh Rails app and then run something like this:
rails g scaffold position_list name
rails g scaffold position first_name last_name position_list:references
This will give you position_list.positions to get all positions for any position_list or Position.all for a list of all positions.
Also it sounds like a lot of Rails is new to you. Hartl's classic is a great intro: http://ruby.railstutorial.org/ruby-on-rails-tutorial-book
My goal is to display select box for each relation for users and specific project.
All users need to be listed but only project users have some type of relation. Other users have none selected in theirs select box.
I have this model:
class Project < ActiveRecord::Base
belongs_to :company
has_many :tasks, :order => 'state_type_id ASC'
has_many :project_user_relations
has_many :users, :through => :project_user_relations
def t_name
name.camelcase
end
end
class User < ActiveRecord::Base
belongs_to :company
has_many :tasks , :foreign_key => :assigned_user_id
has_many :project_user_relations
has_many :projects, :through => :project_user_relations
def full_name
firstname + ' ' + lastname
end
def relation_to(project)
relation=ProjectUserRelation.find_by_project_id_and_user_id(project.id, id)
relation ||= relation=ProjectUserRelation.new
end
end
class ProjectUserRelation < ActiveRecord::Base
belongs_to :project
belongs_to :user
has_one :project_user_relation_type
end
class ProjectUserRelationType < ActiveRecord::Base
def t_name
I18n.t("app.projects.users.relation.type."+code)
end
end
I want make a form to display all users, with collection_select.
I used code:
def edit_all
#project = Project.find(params[:project_id])
#users = User.all
....
in my controler
routes works ok.
in my view:
<% #users.each do |user| %>
<%= f.fields_for :users, user do |user_fields| %>
<tr class="reference" rel="<%= parent_user_path(user) %>" >
<td class="name"><%= link_to user.full_name, parent_user_path(user) %></td>
<td class="email"><%= mail_to user.email %></td>
<td class="type">
<%= user_fields.fields_for user.relation_to #project do |relation_fields| %>
<%= relation_fields.collection_select :project_user_relation_type, ProjectUserRelationType.all, :id, :t_name, {:include_blank => false, :prompt => t("helpers.select.prompt") } %>
<% end %>
</td>
</tr>
<% end %>
<% end %>
or for test:
<%= f.fields_for :users, #users do |xuser_fields| %>
<% logger.debug "#{self.to_s} xuser_fields = #{xuser_fields.object.inspect} ;" %>
<tr>
<td><%= xuser_fields.text_field :firstname %></td>
<td></td>
<td></td>
<td></td>
</tr>
<% end %>
but notnihng woks right
first one generates wrong name in html:
select id="project_users_project_user_relation_project_user_relation_type" name="project[users][project_user_relation][project_user_relation_type]"
second one generates error:
undefined method `firstname' for # Array:0x4d03658
Can you help me to solve this situation.
PS:sorry for long code :(
SOLUTION (probably - solved by reading RoR sources)
I found sollution i thing.
A method
def name_attributes=(attributes)
# Process the attributes hash
end
in Project model was missing.
It is unbelievable sollution :].
There is also exact syntax after fields_for: :name, #some_collection, where name must be exactly same name as in the beginign of mentioned def in Model.