Rails - nested loops inside view - ruby-on-rails

I'm taking up rails as a hobby but I'm still fairly new so apologies if this sounds ridiculous. I'm creating a board that can have many statuses. And each status can have many notes. However, this error comes up once I added the notes loop into the status loop on the view:
undefined method `notes' for nil:NilClass
Snippet of the boards/show.html.erb file:
<% #board.statuses.each do |status| %>
<div>
<h2><%= link_to status.name, status_url(status)%></h2>
<% #status.notes.each do |note| %>
<h2><%= link_to notes.content, note_url(note)%></h2>
<% end %>
<%= link_to 'New notes', new_note_path(#note) %>
</div>
<% end %>
I'm not sure if I'm doing something wrong within the controllers or the view though. I've been having a hard time figuring it out. I appreciate any help though!
notes_controller:
class NotesController < ApplicationController
def new
#note = Note.new
end
def create
Note.create(note_params.merge(status_id: current_user.id))
redirect_to boards_url
end
def delete
Note.find(params[:id]).destroy(note_params)
end
def update
Note.find(params[:id]).update(note_params)
end
def note_params
params.require(:note).permit(:status_id, :content)
end
end
statuses_controller:
class StatusesController < ApplicationController
def new
#status = Status.new
end
def create
Status.create(status_params.merge(board_id: current_user.id))
redirect_to :root
end
def delete
Status.find(params[:id]).destroy(status_params)
end
def update
Status.find(params[:id]).update(status_params)
end
def show
#status = Status.find(params[:id])
end
def status_params
params.require(:status).permit(:board_id, :name)
end
end
Any more information required then let me know. Thank you. :)

I'm thinking it should look more like:
<% #board.statuses.each do |status| %>
<div>
<h2><%= link_to status.name, status_url(status)%></h2>
<% status.notes.each do |note| %>
<h2><%= link_to notes.content, note_url(note)%></h2>
<% end %>
<%= link_to 'New notes', new_note_path(#note) %>
</div>
<% end %>
So that you're using the notes from the status in a given loop.

The error you're getting is because in this line <% #status.notes.each do |note| %> the view is expecting to be passed #status object from the show action in the board's controller. Since you aren't passing that #status, it's nil and nil doesn't have the method notes.
As #jvillian pointed out, it should be <% status.notes.each do |note| %> because you want to get the notes from the statuses you're iterating over with each in this line: <% #board.statuses.each do |status| %>

Related

act_as_followers get all posts of user I'm following

Im trying to get all the Posts from the the Users. I'm following using the act_as_follower gem. The User follows a profile model, and Posts belong to a User.
My User model:
acts_as_follower
My Profile model the user follows:
belongs_to :user
acts_as_followable
Post model:
belongs_to :user
My Post Controller.rb:
def follow
#profile = Profile.find(params[:id])
current_user.follow(#profile)
redirect_to :back
end
def unfollow
#profile = Profile.find(params[:id])
current_user.stop_following(#profile)
redirect_to :back
end
Im trying to implement something like this using follows_by_type method provided:
#posts = current_user.follows_by_type('Post').order("created_at DESC")
But the thing is the User follows the Profile model, but here I'm looking for a type 'Post'.
EDIT
In my index controller i'v set up the following:
#favoritePost = Post.where(user_id: current_user.all_follows.pluck(:id))
And in the view iv implemented this:
<% if user_signed_in? %>
<%#favoritePost.each do |post| %>
<%= post.title %>
<% end %>
<% end %>
The gem lets you follow multiple models and follows_by_type('Post') filters the Posts you follow.
What you're looking to do is to return the posts from the users you follow.
Controller
#posts = Post.where(user_id: current_user.all_following.pluck(:id))
View
<% #posts.each do |post| %>
<%= post.title %>
<% end %>
I worked out this solution, might not be the best, but it works as required.
In my controller i set this up:
#following = current_user.all_following
#followposts = #following.each do |f|
f.user.id
end
And in my view I have set this up:
<% #followposts.each do |f| %>
<% f.user.posts.each do |g| %>
<%= g.title %>
<% end %>
<% end %>

undefined method `to_key' for #<User::ActiveRecord_Relation:0x007f1bf8c2fd60>

I am really new at rails so please forgive me if i can't see it.
I am trying to edit the permissions on each individual user and i am getting this error in form_for:
undefined method `to_key' for #<User::ActiveRecord_Relation:0x007f1bf8c2fd60>
From what i have seen on other questions on stackoverflow, this usually happens when you try to call a collection in a form but this is not the case?
view:
<div class="n-container">
<tr-form data-riot riot-tag="tr-form">
<%= form_for(#user) do |f| %>
<section>
<div class="w-container">
<h1>User permissions</h1>
<% #permissions.each do |permission| %>
<%= check_box_tag 'permission_ids[]', permission.id %>
<div>
<%= permission.description %>
</div>
<% end %>
</div>
</section>
<section>
<div class="f-controls align-right">
<%= f.submit class: "btn fill blue", value: "Submit" %>
</div>
</section>
<% end %>
</tr-form>
</div>
users_controller:
class UsersController < ApplicationController
def user_params
params.require('user').permit(
permissions: []
)
end
def permissions
#user = User.where(id: params[:user_id])
#permissions = Permission.all
end
end
routes:
resources :users do
get 'permissions'
post 'permissions'
end
Thank you in advance!
One should use ActiveRecord::FinderMethods#find, not where, to receive a single instance:
def permissions
# WRONG: where returns a relation
# #user = User.where(id: params[:user_id])
#user = User.find(params[:user_id])
#permissions = Permission.all
end
It worth to mention, that find raise a RecordNotFound exception on fail, hence you probably want to rescue from it:
def permissions
#user = User.find(params[:user_id])
#permissions = Permission.all
rescue RecordNotFound => rnf
# Log or just skip
end
where might be [ab]used here as well, but in such a case you need to explicitly say that you need the only user:
#user = User.where(id: params[:user_id]).first

How can I order posts in descending order

I'm making a blog type site, and I'd like the posts to be displayed newest first(descending order) Ive tried a few different things and haven't been able to figure it out. This is my current code:
post.html.erb
<%= #posts.each do |post|%>
<div>
<p><%= avatar_for(post.user, size: 40) %>
<%= link_to post.username, post.user %></p>
<h2>
<%= link_to post.title, post %>
</h2>
</div>
<% end%>
post controller
class PostsController < ApplicationController
before_action :authenticate_user!
def posts
#posts = Post.all.order("created_at DESC")
end
def new
#post = Post.new
end
def create
#post = current_user.posts.new(post_params)
if #post.save
redirect_to post_path(#post)
else
render :new
end
end
def show
#post = Post.find(params[:id])
end
private
def post_params
params.require(:post).permit(:title, :body, :all_tags)
end
end
I believe, based on the Guide, that the syntax you're looking for is:
Post.order(created_at: :desc)
See if that works for you.
This should be #posts as you are calling #posts in you post.html.erb to retrieve and display all the posts:
def posts
#posts = Post.all.order("created_at DESC")
end
The method should look like
def posts
# Plural #posts
#posts = Post.all.order(created_at: :desc)
end
Just a small fix, in your posts method you're declaring #post variable but in the ERB file you're calling #posts.
That should be giving you a Nil error. Declare #posts (plural), and then your ERB file with better indentation:
<%= #posts.each do |post| %>
<div>
<p>
<%= avatar_for(post.user, size: 40) %>
<%= link_to post.username, post.user %>
</p>
<h2>
<%= link_to post.title, post %>
</h2>
</div>
<% end%>
In case this question hasn't been answered yet:
It looks like the problem is coming from the name of the method in your PostsController.
You're expecting to have access to #posts from a method called posts, but your file name for the view you're trying to render is post.html.erb. I believe it should be posts.html.erb.
Why not call it index? That's the Rails convention.
As others have said, the query is correct. Hope this helps.

Rails 4 - Render controller variable

I'm a Rails newbie and this seems like a trivial thing, but I can't figure out how to render this.
I have a form that takes in a string input:
<%= form_for #idea do |f| %>
<div>
<%= f.label :idea_list %>
<%= f.text_field :idea_list %>
</div>
<%= f.submit %>
<% end %>
And a controller:
class IdeasController < ApplicationController
def index
end
def new
#idea = Idea.new
end
def create
#idea = Idea.new(idea_params)
if #idea.save
render :index
else
render 'new'
end
end
private
def idea_params
params.require(:idea).permit(:idea_list)
end
end
I then want to render the idea_list parameter in index.html.erb, but cannot figure out how to do so. I've tried:
<p><%= #idea %></p>
but I get an output of #<Idea:0x007f8b16d98638>.
<% #idea do |idea| %>
<p><%= idea.idea_list %></p>
<% end %>
I've tried many variations of this but keep getting various errors.
Please help.
So #idea is an instance of an object. idea_list is an attribute. So you need to call #idea.idea_list. Any time you want to reference an instance of an object / model from a controller it's going to #instance.attribute.
In your case, it's going to be
<p><%= #idea.idea_list %></p>
If you want to show them from a list of the all, in your view it's
<%#ideas.each do |idea| %>
<p><% idea.idea_list%></p>
<% end%>
And in your controller it's
def index
#ideas = Idea.all
end

Getting undefined method `errors' for nil:NilClass Ruby on Rails Guide

Okay, I've been searching for a question here thats exactly the same as mine and I can't find one, so I'm forced to ask it myself. I'm following the guide on here: http://guides.rubyonrails.org/getting_started.html
I ran into this error saying: "undefined method `errors' for nil:NilClass" for my Edit Article page.
Here is my extracted source:
<h1>Editing article</h1>
<%= form_for :article, url: articles_path(#article), method: :patch do |f| %>
<% if #article.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#article.errors.count, "error") %> prohibited
this article from being saved: </h2>
And here is my trace:
app/views/articles/edit.html.erb:4:in block in _app_views_articles_edit_html_erb___778692675__618464548
app/views/articles/edit.html.erb:3:in _app_views_articles_edit_html_erb___778692675__618464548
Here is my action Controller
class ArticlesController < ApplicationController
def new
#article = Article.new
end
def edit
#articles = Article.find(params[:id])
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def show
#article = Article.find(params[:id])
end
def index
#articles = Article.all
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
end
private
def article_params
params.require(:article).permit(:title, :text)
end
end
And here is my edit.html.erb
<h1>Editing article</h1>
<%= form_for :article, url: articles_path(#article), method: :patch do |f| %>
<% if #article.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#article.errors.count, "error") %> prohibited this article
from being saved: </h2>
<ul>
<% #article.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 :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
Variable Definition
Something you might want to consider, alongside Arup's answer, is the error itself:
"undefined method `errors' for nil:NilClass"
What you're getting back is an exception because you're trying to call a method on a nil class object. As Arup pointed out, this is generally caused by your calling of an #instance_variable without defining it first
I want to highlight the fact that your error says the problem is you have an undefined method for your object. Most would treat the problem as your method is undefined for some reason; in reality the problem is you don't have the object defined.
--
Fix
The way to fix the error, as pointed out by Arup is to reference the #instance variable that's defined in the edit method, like this:
#app/controllers/articles_controller.rb
Class ArticlesController < ApplicationController
def edit
#article = Article.find params[:id]
end
end
#app/views/articles/edit.html.erb
<%= #article.errors %>
Something else you will want to consider is the following:
#app/views/articles/edit.html.erb
<%= form_for #article do |f| %>
# ...
<% end %>
Yes, you have a typo with the instance variable.
<% if #article.errors.any? %>
should be
<% if #articles.errors.any? %>
Because inside the controller action #edit, you have defined #articles not #article. But it should be named #article since it's a single article. Thus keep <% if #article.errors.any? %> as it is, change the #edit method as
def edit
#article = Article.find(params[:id])
end
Remember instance variables returns nil, if you attempt to use it before defining it in Ruby. The same happened in your case. You defined #articles, but used #article, which was not defined by you before attempting to use it, thus returns nil. And nil.errors throws the error as you see.
The problem is that #article is nil (null)
In your controller, edit the new action, so it looks like this:
def new
#article = Article.new
end
Refresh the web page, and there is no more error.
Edit new action in controller
def new
#article = Article.new
end
Since your instance of article is nill.

Resources