Reference one model from another model - ruby-on-rails

I would like to reference images in buildings/index.html.erb. I have:
class BuildingsController < ApplicationController
def index
#buildings = Building.all
#images = #buildings.images.all
end
end
class Building < ActiveRecord::Base
has_many :images
end
class Image < ActiveRecord::Base
belongs_to :building
end
buildings/index.html.erb:
<% #buildings.each do |building| %>
<% if #buildings.images.any? %>
<% #buildings.images.name %>
<% end %>
<% end %>
I get the following error: undefined method images for <Array:0x000001109b4680>

#buildings is an array of Building objects. Every Building object has its images method. You might iterate over the #buildings array and call the images method of every member.
<% #buildings.each do |building| %>
This is Building with ID <%= building.id %>.
<% if building.images.any? %>
...
<% end %>
<% end %>
Also, you don't need the #images variable in your controller.

You're not iterating over your buildings. You need to grab each one and then do what you were trying to do:
<%- #buildings.each do |building| %>
<%- if building.images.any? %>
...
<%- end %>
<%- end %>
You can also do:
index.html.erb
<%= render #buildings %>
This will take each Building object and pass it to a _building.html.erb partial where you can then do
_building.html.erb
<%- if building.images.any? %>
...
<%- end %>

Related

Where's the textNode in the view coming from?

# controller
def index
#teams = TeamMember.where(user: current_user)
end
# view
<%= #teams.each do |t| %>
<h2><%= t.project.name %></h2>
<p>Where's the line below this coming from?</p>
<!-- what's happening here? -->
<% end %>
The result in the browser looks as follows. It returns #projects as a string. Where is this coming from and how do I remove it?
ERB
You trigger ERB by using embeddings such as <% %>, <% -%>, and <%= %>. The <%= %> tag set is used when you want output.
You have used <%= %> for looping projects and the block form of Array#each returns the original Array object, which is why it prints the projects result at the end.
you have to use <% %> for #projects.each do |p| instead of <%= %>
# view
<% #projects.each do |p| %>
<h2><%= p.name %></h2>
<% end %>
Team member Model
class TeamMember < ApplicationRecord
belongs_to :user
belongs_to :project
end
User Model
class User < ApplicationRecord
has_many :team_members
end
Project Model
class Project < ApplicationRecord
has_many :team_members
end
Controller
def index
#teams = current_user.team_members
end
View
<% #teams.each do |t| %> // Remove '=' from the loop itereation
<h2> <%= t.project.name %> </h2>
<% end %>

Map modelA to modelB in controller

I have two unassociated models which normally would be associated. This is however sort of a freak-case where I don't want them to be associated.
In the view, I can do this:
<%= #user.each do |user| %>
<%= Option.where(:id => user.option_1).or(Option.where(:id => user.option_2).each do |option| %>
<% end %>
<% end %>
How can I move that logic to the controller?
If I, in controller do
#user = User.all.map do |user|
#options = Option.where(:id => user.option_1).or(Option.where(:id => user.option_2)
end
The results of #options do not map to the #user object the same way it would #user.options if models were associated.
Is there a way to mimic that functionality when the models are not associated so that when I loop through <% #users.each do %> I can access <% #options.each do %> within that scope the same way I would if :options belonged to :user and :user had many :options
So that the final output in the view would look like this:
<% #users.each do |user| %>
<% #options.each do |option| %>
#Outputs the result of Option.where(:id => user.option_1).......
<% end %>
<% end %>
Since you want to loop options, you should do this
In controller
#options = Option.joins("INNER JOIN users ON users.option_1 = options.id OR users.option_2 = options.id").distinct
In view,
<% #options.each do |option| %>
<% end %>
Give it a try.

Rails 4 fields_for not displaying or updating

I have a nested relationship where dashboard has many rewards, and I am trying to add a fields_for to the page in order to edit the rewards. Unfortunately, it doesn't seem to be working and I don't know why.
Here's what I have.
Dashboard model:
class Dashboard < ActiveRecord::Base
belongs_to :manager
has_many :rewards
accepts_nested_attributes_for :rewards, allow_destroy: true
end
Rewards model:
class Reward < ActiveRecord::Base
belongs_to :dashboard
end
Dashboard controller:
class DashboardsController < ApplicationController
before_action :authenticate_manager!
# Requires user to be signed in
def index
#dashboards = Dashboard.all
end
def new
#dashboard = Dashboard.new
end
def edit
#dashboard = Dashboard.find(params[:id])
end
def create
#dashboard = Dashboard.new(dashboard_params)
#dashboard.save
if #dashboard.save
redirect_to dashboard_path(#dashboard)
else
render :action => new
end
end
def update
#dashboard = Dashboard.find(params[:id])
if #dashboard.update(dashboard_params)
redirect_to :action => :show
else
render 'edit'
end
end
def show
#dashboard = Dashboard.find(params[:id])
end
def destroy
#dashboard = Dashboard.find_by_id(params[:id])
if #dashboard.destroy
redirect_to dashboards_path
end
end
private
def dashboard_params
args = params.require(:dashboard).permit(:title, :description, :rewards, {rewards_attributes: [ :id, :title, :referralAmount, :dashboardid, :selected, :_destroy] } )
args
end
end
Form in dashboards view:
<%= form_for :dashboard, url: dashboard_path(#dashboard), method: :patch do |f| %>
<% if #dashboard.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#dashboard.errors.count, "error") %> prohibited
this dashboard from being saved:
</h2>
<ul>
<% #dashboard.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :description %><br>
<%= f.text_field :description %>
</p>
<%= f.fields_for :rewards do |reward| %>
<%= reward.label :title %><br>
<%= reward.text_field :title %>
<%= reward.check_box :_destroy %>
<%= reward.label :_destroy, "Remove reward" %>
<% end %>
<p>
<%= f.submit %>
</p>
<% end %>
I went ahead and manually added rewards to the database through the rails console and it worked beautifully, but they are not showing up on the page. They will show up if I iterate through them like so
<% if #dashboard.rewards.any? %>
<ul>
<% #dashboard.rewards.each do |reward| %>
<li><%= reward.title %></li>
<li><%= reward.referralAmount %></li>
<% end %>
</ul>
<% else %>
<p>no rewards</p>
<% end %>
However the fields_for does not display the rewards or their content and resultingly allow one to edit them.
Let me know if you need further information/code.
Try to modify your:
View:
<% if #dashboard.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#dashboard.errors.count, "error") %> prohibited
this dashboard from being saved:
</h2>
<ul>
<% #dashboard.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= form_for #dashboard, url: dashboard_path(#dashboard) do |f| %>
........
<% end %>
Controller (has_many relationship):
def new
#dashboard = Dashboard.new
#dashboard.rewards.build
end
private
def dashboard_params
params.require(:dashboard).permit(:title, :description,
rewards_attributes: [
:id,
:title,
:referralAmount,
:dashboardid,
:selected,
:_destroy
])
end
You don't have to set the method: patch if form.
Once you got in edit page, Rails will use the update action in controller when form submission.
To check it, run rake routes,
you will see somsthing like this:
PATCH /dashboards/:id(.:format) dashboards#update
PUT /dashboards/:id(.:format) dashboards#update
In controller you need to give build
def new
#dashboard = Dashboard.new
#dashboard.rewards.build
end
"build" is just create a new object in memory so that the view can take this object and display something, especially for a form.
Hope it helps for you
You should build object before nested form. You can add whatever you want that object.
Try it in controller;
def new
#dashboard = Dashboard.new
3.times do
#dashboard.build_reward
end
end
Try setting an "#rewards" instance variable in your dashboards edit method (where #rewards = #dashboard.rewards). Then replace :rewards with #rewards.
Edit:
I believe my initial answer is inapproriate for your exact question (while it would be helpful on say the page to show a specific dashboard and its rewards). The answers above are on the right track re:
refining your params method per #aldrien.h;
Adding #santosh dadi's suggestion of
#dashboard.rewards.build
(assuming you only want one rewards fields on a form for "new")
Finally though, to avoid making fake information for a new rewards form, adding to the top of your Dashboards model:
accepts_nested_attributes_for :rewards, reject_if: lambda {|attributes| attributes['title'].blank?}
http://guides.rubyonrails.org/form_helpers.html#nested-forms

How to filter associated records from controller in Rails?

I have two models, Article and Comment with a one-to-many relation.
My view looks like this:
<% #articles.each do |article| %>
<% article.comments.each do |comment| %>
some content
<% end %>
<% end %>
It's easy to filter the #articles from the controller, e.g:
#articles = Article.order('created_at asc').last(4)
And I could easily filter the comments in my view:
<% #articles.each do |article| %>
<% article.comments.order('created_at asc').last(4).each do |comment| %>
some content
<% end %>
<% end %>
But I don't want to put the order('created_at asc').last(4) logic in my view. How can I filter the article's comments from within the controller?
You could do something like this in the model
Class Article < ActiveRecord::Base
has_many :comments, -> { order 'created_at' } do
def recent
limit(4)
end
end
end
and then use it as follows in the view
#articles.each do |article|
article.comments.recent.each do |comment|
stuff
end
end
source: https://stackoverflow.com/a/15284499/2511498, props to Shane

has_many and belongs_to nameerror rails

This is my index_controller
def index
#category = Category.all
end
My category model contains
has_many :sub_categories
and my sub_category model contains
belongs_to :category
And here is my view
<% category.sub_categories.each do |f| %>
<li>f.name</li>
<% end %>
I am using rails 4 and am getting error as
undefined local variable or method `category' for #<#<Class:0xab758cc>:0xb56c46d8>
You're just a little bit off with your naming conventions and what sort of code it prompts you to write:
def index
#categories = Category.all
end
#category should be #categories, because Category.all will return an ActiveRecord Relation of 0, 1 or many Category objects, not a single object.
Then:
<% #categories.each do |category| %>
<% category.sub_categories.each do |sub_category| %>
<li><%= sub_category.name %></li>
<% end %>
<% end >
First you iterate over the categories from Category.all, then for each Category, you iterate over its SubCategories.
You have two problems there.
It should be #category, not category
It should be <li><%= f.name %></li>
You missed the reference to the instance variable and the ERB tag to use f.name, it should be
<% #category.sub_categories.each do |f| %>
<li><%= f.name %></li>
<% end %>

Resources