I want to show a post along with the poster's info on my rails app. Right now I'm able to show the post and user association on the "show" page (the page for a single post), but when I want to show it on the "index" page (where all of my posts are), I get this error: undefined method `username' for nil:NilClass
I added #post.user = current_user to my post_controller under "show" (That allowed me to show the poster's info. But i dont know what to add to the "def index".
This is what I have there:
def index
#posts = Post.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #posts }
end
end
This is what I have under "show"
def show
#post = Post.find(params[:id])
#post.user = current_user
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #post }
end
end
I want to know what to add to my def index to be able to display the poster's info. Thanks in advance.
Your set up is wrong. The user needs to be added to the post when it is created and updated.
As you have it now, all posts will always belong to the user that is currently viewing the post because you are assigning the current_user to the post in the show action (and would be doing the same in the index view if you continued with this approach) meaning that when post 1 is viewed by user 1 it would show as belonging to user 1. When post 1 is shown by user 2 it would belong to user 2.
The solution is to assign the current user to the post in the update and create actions of the posts controller exactly as you have it now in the show action but before the post gets physically updated or created.
Then remove the #post.user = current_user from the show action.
This may mean you are left with legacy data in your app that doesn't have a user assigned. But that's o.k., just edit and save each post and it will have you attached automatically.
Then in the views/posts/index_html.erb just add the user details that you want to see in new table row columns before the show/edit links. This is assuming you have a standard scaffolded index.html.erb file. If you don't have a standard index view then put it wherever you want it but then if you had a customised index view you probably wouldn't be asking this question in the first place so forget about that and you'd know where it goes
Update
I did explain how to show the user in the views in my response above but possibly I need to be a little clearer so I'll show you the code.
To show the user name in the show view use
<%= #post.user.name unless #product.user.blank? %>
To show the user in the index action for the post use
<% #posts.each do |post| %> <!-- This is already in your index action. -->
<%=post.user.name unless post.user.blank?%><!-- This is the code you need -->
<!-- You might want to add a new th in the header for the css table then you can add a <td></td> tags round the above line so your table all matches up nicely for display purposes-->
<%end%> <!-- This is already in your index action -->
Hope that helps
Related
Say, I have users list on the '/users' page and 2 actions for the 'user' entity: 'index' (with using of Ajax) and 'destroy'.
def index
...
respond_to do |format|
format.html
format.js
end
end
def destroy
...
redirect_to users_url
end
I want to destroy a user (right from the '/users' page) and use Ajax of the 'index' action after that ('index.js.erb' file) in order to render only a part of the opened '/users' page.
Is it possible to do that?
My current solution right now is to use Ajax for 'destroy' action (a separate 'destroy.js.erb' file) and duplicate needed changes for 'index' page there. But, first of all, it's a code duplication, and second, in this case my pagination links are broken (I use 'Kaminari' gem and looks like it works fine only with 'get' requests, at least by default).
There is a 'view' part of updating with Ajax, if necessary:
<div id="users_table">
<table class="table table-hover table-borderless">
...
<tbody>
<%= render #users %>
</tbody>
</table>
<div><%= paginate #users, remote: true %></div>
</div>
If you want the destroy action to render the index.js.erb:
def destroy
...
respond_to do |format|
format.js { render action: :index}
format.html { redirect_to users_url}
end
end
But, to render index.js you will need to, in your destroy action, rebuild the #users object and ensure you're rebuilding it for the correct page. So, when you call the destroy action you'll need to pass the ID(s) of the user(s) you want to destroy, as well as the page you are on.
Your destroy.js.erb should (on successful destruction) remove the destroyed element from the index by deleting a part of the HTML. I don’t expect that the code to do that duplicates the code you have in the index view.
Post your current destroy.js.erb as well as the relevant part of index.html.erb for more help though.
You can also use redirect within a respond_to so your HTML call will redirect while the Ajax uses destroy.js.erb
respond_to do |format|
format.js
format.html { redirect_to users_url}
You could also hack your way to your answer by calling render :index for the js response. But, if you were to try to render the index view here you’ll definitely get duplication of code, along with an extra DB call and probably some broken pagination. So, I’d recommend that you take the approach I first suggested (use destroy.js.erb to remove that user from the HTML)
Finally, more generally, when you’re trying to avoid duplication of view code; a partial might be the answer
I'm working on an order system, I passed some information about a new order from controller (orders#confirm) to a confirmation page using instance variable (such as #detail). On the confirmation page, users are supposed to confirm the information and submit a form to create the new order (orders#create). If the post action fails, I want it to stay on the same confirmation page and preserve all the information on the page for the user:
def create
#order = Order.new(order_params)
if verify_recaptcha(model: #order) && #order.save
redirect_to items_url
else
render :confirm
end
end
The code is not working because all the variables that I passed from orders#confirm to the confirmation page are lost. I know I can recreate them, but is there any better ways to preserve those information? Thank you very much!
Within your approach, you have to rebuild the #detail object in the current action create in order to make your confirm.html.erb view to be rendered properly.
It is possible. However, I think there is a better way that you can let the user confirms the order by AJAX ( which is dead simple with Rails ) so the user can stay on the page if the confirmation failed.
In your confirm.html.erb, suppose you have a form to let user confirm, just change it to remote: true
<%= form_for #order, remote: true, format: :js do |form| %>
<%# blah blah %>
<% end %>
Modify your controller
def create
#order = Order.new(order_params)
if verify_recaptcha(model: #order) && #order.save
# Redirect when success
render js: "window.location = '#{your_desired_path}'"
else
# Display error to user.
render "ajax_create_error", status: :bad_request
end
end
Now you can create a file name ajax_create_error.js.erb to display error to the user
# app/views/your_controller_name/ajax_create_error.js.erb
alert("Cannot create order");
I have code in my products_controller.rb
def create
#product = Product.new(product_params)
brand = Brand.find(params[:brand_id])
#product.brand = brand
if #product.save
raise "OK"
else
#brand = Brand.find(params[:brand_id])
render 'brands/show'
end
end
After failure of save method, i need to redirect to brands show.html.erb view, which find brand by id and display information about it.
Questions:
Is it right way of doing that
If user manually passed server_id parameter, how can prevent it from executing (SQL injection)? Or how should i check and display error?
How can i display errors in brands/show views outside form ( because i'm storing form in <a data-form="..."> property, so user can't see form until he clicks on link. Even more, i use form_for([#brand,#brand.send(:products).klass.new]))
use redirect_to brands_path(#brand)
I have a folder views/home that contains the initial screen for a Rails app.
For some users, the home.index.html.erb displays a partial containing a list of workorkorders.
In other words I'm fetching a list of workorder and a list of worequests from the home/index.html.erb - therefore, I've added code to read the #workorders and #worequests into the home controller.
This is the code that fetches the workorders:
<% #workorders.notcompl.each do |workorder| %>
The home controller contains this code to fetch the workorders:
def index
#workorders = Workorder.all
I'd like to have _agentopenrequests.html.erb fetch all of the worequests.
So, I added the following to fetch the wore quests:
def index2
#worequests = Worequest.all
But, in the partial thats executed from home/index.html.erb file, how do get the following line to use index2 instead of index?
<% #worequests.notcompl.each do |worequest| %>
Should I put both #worequests and #workorders into index?
UPDATE1
I tried changing the home controller to this:
def index
#workorders = Workorder.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: Workorders3Datatable.new(view_context) }
end
#worequests = Worequest.all
respond_to do |format|
format.html # index.html.erb
end
end
But, I get
DoubleRenderError - Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action.
UPDATE2
Would it make more sense to have the partial in the worequests folder instead of home - so, the worequests controller gets used?
If all index2 does is pull a collection of worequests, you can copy/move it to the index action.
I am trying to continue along the path I was lead down in this post: render show page on submit backbone.js + rails + rails-backbone gem
I am still trying to figure out what I describe in the first paragraph of that question. I was messing around in the firebug console. When I click submit from the root page everything works fine (except the app doesn't navigate to the newly created objects show page). The url changes to http://localhost:3000/#/x (where x is the id of the newly created object). When I click submit again, I get "500 Internal Server Error 22ms". This error comes in the Console > All window with a little red arrow next to it that (when clicked) drops down another section - upon with I click the "HTML" tab - and I get this error:
ActiveModel::MassAssignmentSecurity::Error in UsersController#update
Can't mass-assign protected attributes: created_at, id, updated_at
I think I may have located the issue for this error - I just don't know what to do to fix it. What I think is going on is that I have two different controllers (a home controller, and a users controller) - and both of their index actions define the same thing, here is my users controller index action:
class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
...
end
Here is my home controller index action:
class HomeController < ApplicationController
def index
#users = User.all
end
end
So as you can see, what I think is going on is that when I click submit the first time (from the home page) #users gets set, and the app gets navigated to the new user's show page (although it doesn't which again - ties this all back to my first question - the url changes, but the content of the page does not, the link for my first question is above).
After the url changes to the show page url (without loading the content), I tried submitting another user form with unique input and I get the mass-assign error above. This seems to be because #users has already been set by the home controller...so that when it is called again from the users controller (upon the second submit) it can't be assigned.
How would I fix this? I need both the home controller and the users controller to be able to use #users...I think. And, tying everything back to to my first question here: render show page on submit backbone.js + rails + rails-backbone gem
Can I do something from within the home controller that redirects the newly created user to the show page (maybe in the create, or update method or users controller/or index method of home controller)? Might this solve the issue I have with redirection to the show page from the root page? All the relevant backbone.js (and my root index.html.erb file) code is posted in my first question...please refer to it as it will fill you in on all the backbone details, and what I am really trying to do.
THANKS!
UPDATE
Here is the update action in my users controller (where the error is supposedly coming from):
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
You are not supposed to send created_at and updated_at attributes to server.
You should inspect parameters you are sending and make sure you are not sending these.
By the way, did my other answer help you?
You should not insert or add created_at, id, updated_at these are generated automatically .......