how do I retrieve attributes of different models from controller? - ruby-on-rails

I have a Vendor controller for show:
def show
#vendor = Vendor.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #vendor }
end
end
In my View for Reviews (where Vendor :has_many Reviews)
<% if #vendor.reviews.empty? %>
No Analyst Reports yet
<% else %>
<% for review in #vendor.reviews %>
<%= review.user_id %>
<%= review.summary %><br />
<hr class="span-5" />
<% end %>
<% end %>
So I am basically going through a 'for' loop for all the reviews for a particular vendor (this has been a tricky concept for me but it seems to work).
So: I want to display the User.name and user.email. I know what the user_id for each corresponding Review is (review.user_id) but I don't know how to display values for the User model.
I thought using find_by_id would work but it doesn't recognize User.
Help?

If you've set up a :has_one relationship between the Review model and the User model, then you can just use review.user to access it. So you'd get user attributes with review.user.name, review.user.email, etc.
Note that if you're going to be retrieving many child records to loop through like this, you may want to call find with an :include parameter to reduce the number of queries made. Something like:
Vendor.find(params[:id], :include => { :reviews => :user } )
See the API docs for has_one for more info.

Related

Accessing further objects from the results of a loop in Rails

I don't even know what to search for on this, so I'll just explain what I'm trying to do. On my user index page I'm printing out a list of the latest users with the immediate info (stuff from the users table). How do I go about pulling the latest post by that user, then? I don't know what to do in the controller that will enable me to have access to each result separately.
Here is a simplified view:
<% #users.each do |user| %>
<%= link_to user.username, user_path(user) %><br />
<%= user.email %>
# this is where I would show the user's latest post
<% end %>
controller:
def index
#users = User.order('created_at DESC').paginate(:page => params[:page], :per_page => 24)
#user_latest_post = ???
end
You should set up User so that it has an association with Post. This allows you to access all Posts belonging to that User (like user.posts). This isn't totally necessary for your question, but is probably something you want (or have already done).
Then you need to create a second, scoped association that gets the latest Post. This way you can use includes in your controller and avoid an N+1 issue (otherwise it will do a new query for the latest post every time you iterate through a user with that each block).
Lastly, you need to choose what you want to display about the Post. Convention would have you make a shared "partial" view for Post that you can reuse. This means you can just tell Rails to render user.latest_post and it will know what to do (assuming you've defined this partial).
I give code examples below to explain what I mean:
# models/user.rb
class User < ApplicationRecord
has_many :posts
has_one :latest_post, class_name: "Post", -> { order(created_at: :desc).limit(1) }
end
# controllers/users_controller.rb
def index
#users = User.includes(:latest_post).order(created_at: :desc).paginate(:page => params[:page], :per_page => 24)
end
# views/users/index.erb
<% #users.each do |user| %>
<%= link_to user.username, user_path(user) %><br />
<%= user.email %>
<%= render user.latest_post %>
<% end %>
# views/posts/_post.erb
<%= post.text %>
# or whatever you want here

Rails 4: has_many through associated object never return nil

I have two Model, Post and Category. They are connected by has_many through association. Categorization is the through table.
#post= Post.find(params[:Post_id])
#category = #post.categories
Some of my post are not under any category. It is possible to post without selecting any category. Problem is #category never show nil. I perform this check
<% if #category %>
<% else %>
<% end %>
This code never goes in else block even though there are no categories. Why is that? How can I check nil in this case?
#post.categories returns an activerecord relation,not nil. Because you're using rails I'd check it's presence using present?
<% if #vertiefungsrichtungs.present? %>
# do something
<% else %>
# do something else
<% end %>
Chances are that since you have a potential for multiple categories, that you will want to do something with them, not just check if there are any.
In that case one thing you could do is render a partial for each category:
<%= render partial: my_category, collection: #category, as: :category %>
You should have a partial _my_category.html.erb:
<%= category %>
If there are no categories, no my_category partials will be rendered, so, no need for additional logic in the view.

Having problems with putting database to use

So I have this books database and a burrows database. In burrows, there is a field for book_id and also a field for user_id, so that I can see who burrowed which book.
Now, I am trying to create a controller and view for it but it is not going well really. Right now the view is looking like this:
<% provide(:title, "Burrow") %>
<b align="center">Choose the name of the book you want t burrow'</b>
<%= form_for(#book) do |f| %>
<div class="forms">
<%= f.name %>
<%= f.check_box(:book_id) %>
<%= f.submit 'Submit!' %>
</div>
<% end %>
But this puts me to the problem where it creates an error because I want to put all books into #books in burrows controller. But I dont really see any other way? \
The final idea would be so that I have all the books displayed and after them a checkbox, so I can select which books I want to burrow. And after that I also want a dropdown menu where all users are listed, I can choose to burrow the book for another user, but the default value would be the logged in user but theres time till that. Right now I am struggline to understand, why my solution for listing books does not work?
Listing my controller here also:
class BurrowsController < ApplicationController
before_action :signed_in_user, only: [:index,:edit,:update, :destroy]
before_action :admin_user, only: :destroy
def index
#burrows = Burrow.all
end
def show
#burrow = Burrow.find(params[:id])
end
def new
#burrow = Burrow.new
end
def create
#burrow = Burrow.new(burrow_params)
if #burrow.save
flash[:success] = "Burrowing a book was successful!"
redirect_to #burrow
else
render 'new'
end
end
def listing
#book_list = Book.all
end
# Private section, makes the page unable to be seen for non logged in users
private
def burrow_params
params.require(:burrow).permit(:user_id, :book_id)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
# Redirecting not logged in user etc.
def signed_in_user
unless signed_in?
store_location
redirect_to '/sessions/new', notice: "Please sign in!"
end
end
end
Right now I am struggline to understand, why my solution for listing books does not work?
I'm not sure what listing you mean. The view you pasted apparently corresponds to the controller action Burrows#new?
So I'm going to tell you what's wrong with your view:
<%= form_for(#book) do |f| %>
This prints a form for a Book, not a Burrow. You could create a new book with this form, but that's certainly not what you're trying to do here.
You'll want to have all these variables in your controller:
def new
#users = User.all
#books = Book.all
#burrow = Burrow.new
end
so you can use collection_select with #users, have a #burrow object to use with form_for, and do a each loop on #books, for instance, like this:
<%= form_for(#burrow) do |f| %>
<% #books.each do |book| %>
<%= f.check_box :book_ids, multiple: true, book.id, nil %>
<% end %>
<%= f.collection_select :user_id, #users, :id, :name, {}, selected: current_user.id %>
<%= f.submit %>
<% end %>
Click the links for documentation on these commands: collection_select, check_box
This is not ideal code, but it's as close to your example as I can get.
I understand if you don't get this right away. Your code is a bit of a mess right now and there's too much wrong with it to be explained in one post and fixed by just one line. You might want to start over, and make a single controller action work before you try to make everything at once.
Sometimes it's better to sit back and really think about what you're trying to achieve, and first lay out how to achieve it inside your head; and only then start programming!
It seems to me that you're using the RailsTutorial by Michael Hartl, so all I can recommend to you right now is, read what you've read again more thoroughly and try to stick to his examples first until you feel confident, before really starting to make your very own application.

Couldn't find Post without an ID

I am trying to get my posts tagged with a certain tag to render. My code in the view is
Views/posts/sports.html.erb
<% my_posts = post.find_by_tag("sports") %>
<%= my_posts.each do |post| %>
<%= post.title %><br />
<%= post.body %><br />
<% end %>
my controller for this looks like
def sports
#posts = Post.paginate(:page => params[:page], :per_page => 10)
#post = Post.find(params[:id])
#title = "Newest"
respond_to do |format|
format.html
format.json { render :json => #users }
end
end
I know I have to define the #post variable but I'm not sure what to define it as.
UPDATE
The problem I'm having is a "Couldn't find Post without an ID" error
Second UPDATE
def find_by_tag name
Tag.find_by_name(name).posts
end
Part of the problem, based on what is shown here, is that you are defining instance variables with Post object(s) in the controller, and then not using them for anything in the view. To retrieve a collection of all the posts tagged "sports," you'd do the following in the controller:
#sports_posts = Post.find_by_tag("sports")
and in the view:
<% #sports_posts.each do |post|
etc...
To add pagination, you can just chain that method to the original:
#sports_posts = Post.find_by_tag("sports").paginate(:page => params[:page],
:per_page => 10)
This is different from your snippet, where you define a #posts variable that returns a collection of 10 Post objects, and #post which simply finds a post object based on the id passed by the submitting form params. My guess is that this controller action is not getting created by a form submission, so no params are passed, and therefore params[:id] is nil, hence the error messages you see. In any event, unless you need either of those items in your view (and there's nothing here to suggest they're being used for anything), there's no reason to create them.
What you do need is a collection of posts tagged "sports", which is what the call above accomplishes. It looks like you are trying to do that with post.find_by_tag("sports") in the view. The problem is that you are calling the find_by_tag method on post, which doesn't exist. Post exists - that's the Post class, and probably what you mean to be calling. Just changing post to Post would probably get you where you want, but content retrieval and presentation are better separated if you create your objects in the controller and then use the view to simply render their attribute data (per the example above).
You don't say what's going wrong, you only say what you're trying to do.
A few things to help debug whatever it is you are seeing:
<%= debug(params) if Rails.env.development? %>
In your main layout, this will dump the params hash and may lend a clue.
Also,
rake routes
Make sure you are looking for the right parameter key(s).
In the snippet you provided, you have an equals in front of the my_posts.each ... line, I am not an ERB expert, but I would think you would not want that, instead this:
<% my_posts = post.find_by_tag("sports") %>
<% my_posts.each do |post| %>
<%= post.title %><br />
<%= post.body %><br />
<% end %>

How do I display "wall posts" on a user's page?

I'm trying to show "wall posts" that all users have made on a specific user's page, but I'm having difficulty showing the correct posts.
Users controller:
def show
#user = User.find_by_cached_slug(params[:id])
#posts = Post.find_all_by_poster(params[#user.id])
if signed_in?
#post = Post.new
end
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #user }
end
end
Post form:
<%= form_for #post do |f| %>
<div class="field">
<%= f.text_area :content %>
</div>
<div class="field">
<%= f.hidden_field :user_id, :value => current_user.id %>
</div>
<div class="field">
<%= f.hidden_field :poster, :value => #user.id %.
</div>
<div class="actions">
<%= f.submit "Submit" %>
</div>
<% end %>
When a user creates a post the current_user id is saved in the posts table as the :user_id and the user id of the user's page they're posting on is saved as :poster. This part is working, but I don't understand how to render #posts so that only the posts that have been made on that user's page appear.
The approach I'm trying is somehow showing/filtering? all posts where :poster matches the user id of the user's page; however, I don't know how to make this work or if there is a better way. Any help?
Note: I'm using the slugged gem. In the Users/show view, I use <%= render #posts %>. Eventually, I'd like for users to be able to comment on posts, if that affects any design decisions.
Thanks very much for your help! Please let me know if any more information is needed.
I think this line is the issue:
#posts = Post.find_all_by_poster(params[#user.id])
#user is the the record for the user who wall is now being viewed. (right?) You need all the posts that were posted to that users wall that is all the Post records where poster == #user.id. There is no need to look in the params hash for this. I believe that this line should instead be:
#posts = Post.find_all_by_poster(#user.id)
If this is incorrect, it means that I am not clear how your show action is meant to work. There are two different things that could be #user. By convention this should always refer to the record of the person at the other end of the connection. In your case, it looks like it instead refers to the person whose wall is being viewed. Is that correct?

Resources