I'm trying to create an index page where all assets are displayed including a link to the user who they are assigned to, however when I use
def index
#assets = Asset.paginate(page: params[:page])
#user = User.find(params[:id])
end
It returns - couldn't find User without an ID.
index.html.erb - Assets
<%= provide(:title, 'Assets') %>
<h1>All assets</h1>
<%= will_paginate #assets %>
<ol class="assets">
<%= render #assets %>
</ol>
<%= will_paginate #assets %>
_asset.html.erb partial
<li>
<span class="id">JTC<%= asset.id %></span>
<span class="serial"><%= asset.serial_no %></span>
<span class="status">Status: <%= asset.status %></span>
<span class="type">Type: <%= asset.asset_type %><br/></span>
<span class="description">Description: <%= asset.asset_description %><br /></span>
<span class="comment"><em><%= asset.comment %></em></span>
<span class="timestamp">
<br />Added <%= time_ago_in_words(asset.created_at) %> ago. <br /> Assigned to: <%= link_to
#user.name %>
<br />Date Purchased: <%= asset.date_purchased %>
</span>
</li>
#user = User.find(params[:id]) is expecting a URL along the lines of /assets/40, where 40 is the id (and even then that wouldn't make sense, since the 40 should be the id of the asset, not the user). When you just access /assets, there is no id parameter, so it tries to basically do User.find(nil), which gives you that error.
Assuming assets belong to users, you should just get rid of the #user = User.find(params[:id]) line in your controller, and change your partial to use asset.user.name instead of #user.name.
To avoid an N+1 query situation on your users, you could update your controller to use this:
#assets = Asset.includes(:user).paginate(page: params[:page])
Related
I am trying to create Comments on User created Articles in Rails 5.1.
After a Comment is submitted, the redirect should be to the '/articles/:id' but is instead redirecting to '/articles/:id/comments'.
I'm using nested routing in routes.rb:
devise_for :users
root to: "articles#index"
resources :articles do
resources :comments
end
My CommentsController.rb:
class CommentsController < ApplicationController
before_action :set_article
def create
unless current_user
flash[:alert] = "Please sign in or sign up first"
redirect_to new_user_session_path
else
#comment = #article.comments.build(comment_params)
#comment.user = current_user
if #comment.save
flash[:notice] = "Comment has been created"
else
flash.now[:alert] = "Comment not created correctly"
end
redirect_to article_path(#article)
end
end
private
def comment_params
params.require(:comment).permit(:body)
end
def set_article
#article = Article.find(params[:id])
end
end
The form for Comments in articles/show.html.erb:
<!--Start of comments-->
<div class="col-md-12">
<%= form_for [#article, #comment],
:html => {class: "form-horizontal", role: "form"} do
|f| %>
<% if #comment.errors.any? %>
<div class="panel panel-danger col-md-offset-1">
<div class="panel-heading">
<h2 class="panel-title">
<%= pluralize(#comment.error.count, "error") %>
prohibited this comment from being saved:
</h2>
<div class="panel-body">
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
</div>
</div>
<% end %>
<div class="form-group">
<div class="control-label col-md-2">
<%= f.label :body, 'New Comment' %>
</div>
<div class="col-md-10">
<%= f.text_area :body, rows: 10, class: "form-control", placeholder: "New Comment" %>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<%= f.submit "Add Comment", class: "btn btn-primary btn-lg pull-right" %>
</div>
</div>
<% end %>
</div>
How do I make this submit button save and redirect back to 'articles/:id'? Thanks in Advance.
The routes generated by in your router will look something like this:
/articles/:article_id/comments/:id
This means, when you need to load your article in the CommentsController, you should do something like this (as suggested by #Marlin):
def set_article
#article = Article.find(params[:article_id])
end
Otherwise, you run the risk of attaching the comment to the incorrect article if there happens to be an ID collision between the IDs in the comments and article table. Or you simply get a ActiveRecord::RecordNotFound error.
But I know, that this doesn't answer your question directly, ut I suspect that the issue is that you're loading the wrong record from the db somewhere because of the above mentioned.
Try updating your code, and write a test, to make sure that you can programmatically reproduce the error :)
Here is the users show view where they are supposed to show up. ..
edit (I have updated this post slightly you can see it at RoR: How can I get my microposts to show up?)
<section>
<div id= "purchases">
<%= render 'shared/micropost_form_purchase' %>
</div>
<div id="sales">
<%= render 'shared/micropost_form_sale' %>
</div>
</section>
<div id="purchases list">
<ol class="microposts">
<%= render #purchases unless #purchases.nil? %>
</ol>
</div>
<div id="sales list">
<ol class="microposts">
<%= render #sales unless #sales.nil? %>
</ol>
</div>
so the forms (partials) are loading fine, but then when I make a post, in either one, neither the purchases list nor the sales list shows up. I checked the database and they are being created along with an entry in the column indicating kind (either sale or purchase)
Here are the forms:
<%= form_for (#micropost) do |f| %>
<div class="field no-indent">
<%= f.text_area :content, placeholder: "What's something else you want to buy?" %>
<%= hidden_field_tag 'micropost[kind]', "purchase" %>
</div>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
and
<%= form_for (#micropost) do |f| %>
<div class="field no-indent">
<%= f.text_area :content, placeholder: "What's something else you want to buy?" %>
<%= hidden_field_tag 'micropost[kind]', "sale" %>
</div>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
also, here is the show part of the users_controller.rb
def show
#user = User.find(params[:id])
#micropost=Micropost.new
#microposts = #user.microposts.paginate(page: params[:page])
end
and here is the show part of the microposts_controller.rb
def show
#micropost = Micropost.find(params[:id])
#microposts = Micropost.where(:user_id => #user.id)
#purchases = #microposts.where(:kind => "purchase")
#sales = #microposts.where(:kind => "sale")
end
can anyone help me out? anything else i need? hmmm
First, just to be sure you are getting the results you want, you should try something like this in your view
<%= #sales %>
This should be a hash of the results you want. Then, if that looks good, you want to do something like this
<div id="sales_list">
<ol class="microposts">
<% if #sales.any? %>
<% #sales.each do |sale| %>
<li><%= sale %></li>
<% end %>
<% end %>
</ol>
</div>
And repeat for purchases
Right now I am listing all of a users microposts using the code below.
<div class="span8">
<% if #user.microposts.any? %>
<h3>Purchases I am interested in (<%= #user.microposts.count %>)</h3>
<ol class="microposts">
<%= render #microposts %>
</ol>
<%= will_paginate #microposts %>
<% end %>
</div>
and the view that renders for _micropost.html.erb is as follows
<li>
<span class="content"><%= micropost.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
</span>
<% if current_user?(micropost.user) %>
<%= link_to "delete", micropost, method: :delete,
confirm: "You sure?",
title: micropost.content %>
<% end %>
</li>
so this works fine, however I am changing things up. Every micropost has a hidden_tag_field which is a string (and a column in the database) that is called kind. It can be either "purchase" or "sale". I want to list all of the purchase microposts in one place and all the sale microposts in another. How can I change the micropost view to do this?
Controller:
#purchases = #microposts.where(:kind => 'purchase')
#sales = #microposts.where(:kind => 'sale')
View:
<h2>Purchases</h2>
<%= render #purchases %>
<h2>Sales</h2>
<%= render #sales %>
Anyone else working through Chapter 11 Exercises for Michael Hartl's Rails Tutorial 2nd Edition?
Chapter 11, Exercise 3 asks:
Refactor Listing 11.31 by adding partials for the code common to the following/followers pages, the Home page, and the user show page.
I'm not seeing anything worth refactoring in the homepage, user show page, or the show_follow page
If anyone came up with something worthwhile for this exercise, would love to know.
Thanks!
You can refactor the first block of code from Listing 11.31:
<section>
<%= gravatar_for #user %>
<h1><%= #user.name %></h1>
<span><%= link_to "view my profile", #user %></span>
<span><b>Microposts:</b> <%= #user.microposts.count %></span>
</section>
because it is essentially the same as the views\shared_user_info.html.erb partial used on the home page (Listing 10.32). Therefore, you can replace the block of code above with this:
<%= render 'shared/user_info' %>
Note that you will also need to add <% #user ||= current_user %> to the top of the views\shared_user_info.html.erb partial (which is the same as what was necessary to add to the stats partial in Listing 11.20).
Additionally, there is some duplication (though not exact duplication) between the feed_item + feed partials with the user + micropost partials, where depending on which page is being displayed (follow_show, home, or profile) there are one or more elements being listed (name, gravatar, admin delete link, micropost content, micropost time stamp, and micropost delete link). Those could probably be refactored too to eliminate the feed_item+feed partials and replace them with a combination of the user + micropost partials depending on the page.
I just worked through this exercise and found a solution that works.
First I changed around app/views/shared/_user_info.html.erb to use the #user variable if it is set, and the current_user variable otherwise.
app/views/shared/_user_info.html.erb:
<% if #user %>
<%= link_to gravatar_for(#user, size: 52), #user %>
<h1>
<%= #user.name %>
</h1>
<span>
<%= link_to "view my profile", #user %>
</span>
<span>
<%= pluralize(#user.microposts.count, "micropost") %>
</span>
<% else %>
<%= link_to gravatar_for(current_user, size: 52), current_user %>
<h1>
<%= current_user.name %>
</h1>
<span>
<%= link_to "view my profile", current_user %>
</span>
<span>
<%= pluralize(current_user.microposts.count, "micropost") %>
</span>
<% end %>
Then I replaced the corresponding information in app/views/users/show_follow.hmtl.erb with the partial _user_info.html.erb
app/views/users/show_follow.hmtl.erb:
<div class="row">
<aside class="span4">
<section>
<%= render 'shared/user_info' %>
</section>
<section>
<%= render 'shared/stats' %>
<% if #users.any? %>
<div class="user_avatars">
<% #users.each do |user| %>
<%= link_to gravatar_for(user, size: 30), user %>
<% end %>
</div>
<% end %>
</section>
</aside>
<div class="span8">
<h3><%= #title %></h3>
<% if #users.any? %>
<ul class="users">
<%= render #users %>
</ul>
<%= will_paginate %>
<% end %>
</div>
</div>
I hope this answer helps anyone going through M. Hartl's tutorial.
I have an edit page with the following code, basically a dropdown and button that calls update.
<% form_tag('switch_car', :method => :put) do%>
<div class="field">
<label>Car Name:</label>
<%= select("params", ":id", #available_cars.collect {|v| [v.name, v.id]})%>
</div>
<div>
<%= submit_tag "Switch Car" %>
</div>
<% end %>
The server reads like the params is being set:
Parameters: {"utf8"=>"Γ£ô", "authenticity_token"=>"8vHXrnICaOKrGns6FfMUcd/dWo5kpNKpA8F5l5ozRkY=", "params"=>{":id"=>"9"}, "commit"=>"Switch Car"}
However, when I put the params into a session I get nothing. It seems to be always nil. Not sure what I am doing wrong? Here is code in the controller.
def update
if params[:id]
session[:car_info_id] = params[:id]
redirect_to entry_url
else
redirect_to switch_car_path
end
end
It always gets redirected to the switch_car_path so I am assuming params[:id] is always nil. When I put if params[:id] == nil it goes to the entry_url.
Thanks in advance.
you want params[:params][":id"]
Alternatively, you could put this in your view:<%= select("car_info", "id", #available_cars.collect {|v| [v.name, v.id]})%>
And then in your controller:if params[:car_info][:id]
While the other answer would work, this is probably what you'd want to be doing (using select_tag(:id) will automatically add an :id key/value to the params hash):
<% form_tag('switch_car', :method => :put) do %>
<div class="field">
<label>Car Name:</label>
<%= select_tag(:id, options_from_collection_for_select(#available_cars, "id", "name")) %>
</div>
<div>
<%= submit_tag "Switch Car" %>
</div>
<% end %>
Then you can easily access params[:id] in the controller.