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
Related
I use Devise gem for authentication.
In database I have users table and posts table in my database schema (and Post controller).
In post controller I want to find all posts assigned to specific user. I have user_id in posts table.
How to get all user's posts or how to check if specific post is assigned for SIGNED IN user.
I thought about something like this (of course is only pseudocode:
current_user.id == Post.where(params:[post_id]).user_id
So how to get current user id in Devise and how to check the current user id is the same like eg. user_id assigned to viewing post (I want to add 'edit' function when current user is post owner) and how to find all post which current user is owner.
Associations
Firstly, your user_id column in your posts table is what's known as a foreign_key
Foreign keys are used in relational database systems to give you the ability to call associative data from a single record. Simply, it means that you'll be able to use the ActiveRecord associations to call the data you require, rather than having to call it individually:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :posts
end
#app/models/post.rb
class Post < ActiveRecord::Base
belongs_to :user
end
This will give you the ability to use the following call:
#app/controllers/posts_controller.rb
class PostsController < ApplicationController
def index
#posts = current_user.posts
end
end
You'll be best served looking up the has_many association:
Fix
In regards to showing your posts for your users, you need to be sure that you have the correct "flow" set up. What I mean is you need some condition to know whether your user is signed in & that #posts is set:
#app/views/posts/index.html.erb
<% if #posts.present? %>
<% #posts.each do |post| %>
<%= post.title %>
<% end %>
<% end %>
Maybe this is the first time you use Devise. You can access current_user inside controllers or views. I imagine you could do something like this
In controller (posts_controller.rb):
#posts = current_user.posts
In view (posts/show.html.erb, I guess):
if current_user.id = #post.current_user
#render something here
end
Get all post which current user is owner.
#posts = Post.where(:user_id => current_user.id)
and on your view
<%-# commented : checking if #posts is empty -%>
<% if #posts.empty? %>
<span>Sorry, post is empty </span>
<% else %>
<%= #posts.each do |p| %>
<% if p.user_id == current_user.id %>
<% link_to "edit", edit_path(p) %>
<% end %>
<% end %>
<% end %>
There are many ways you could get current_user posts. I'll go the long way.
we need
an action
an action view and a partial
a route
a link_to
* action *
def my_posts
#posts = current_user.posts.all.order(created_at: 'DESC')
end
* view *
my_posts.html.erb
<% if #posts.present? %>
<%= render 'posts' posts: #posts %>
<% else %>
<h1>You don't have any posts yet! create one</h1>
<% end %>
_posts.html.erb
<%posts.each do |post| %>
<%= post.title %>
<% end %>
index.html.erb
<%= render 'posts' posts: #posts %>
route
get 'post' => 'posts#my_posts', as: :my_posts
link_to
<%= link_to 'My posts', my_posts_path %>
I may be late but someone can find it useful :)
So I have two models, Users that belong_to Organization (which has_many users). I'm using a partial to display all the users that belong to any one particular organization, and this is working fine if I output just the name (it correctly names all the users). However when I change the partial code to provide link_to user.name, the returned links are all links to the parent Organization rather than the individual child objects. What am I doing wrong?
Relevant code:
Organizations Controller
def show
#organization = Organization.find(params[:id])
#users_index = User.joins(:organization).where(organizations: {id: #organization.id})
end
Organization.show.html.erb
<% provide(:title, #organization.organization_name) %>
<h1><%= #organization.organization_name %></h1>
<h2>Your Organization's Users:</h2>
<%= render partial: "users_index", collection: #users_index %>
_users_index.html.erb code:
<p class="users"><%= link_to users_index.name %></p>
If you set up your relationship properly then you can use:
#users_index = #organization.users
And then you need to loop through #users_index and pass that to your partial.
#users_index.each do |user|
<%= render "users_index", :user => user %>
end
And in your partial, change to:
<p class="users"><%= link_to user.name, user %></p>
link_to
I think the core of the issue, as alluded to in the other answer, is your link_to:
<%= link_to users_index.name %>
The link_to helper method basically works like this:
<%= link_to "Your Link Text", link_path %>
I don't see how your application will be able to load the correct link path without your definition, irrespective of whether you added it to the helper or not.
I presume that your rendered link will point to "#", not the "parent object" as you alluded.
--
Fix
I'd do this:
#app/views/organization/show.html.erb
<%= render partial: "users_index", collection: #users_index, as: :user %>
#app/views/organization/_users_index.html.erb
<p class="users"><%= link_to user.name, user %></p>
This should set the correct link_to helper method for you
--
Models
Further, I would also address the associations in your models
You're currently calling users in the most inefficient way. ActiveRecord associations work to remedy this:
#app/models/user.rb
Class User < ActiveRecord::Base
belongs_to :organization
end
#app/models/organization.rb
Class Organization < ActiveRecord::Base
has_many :users
end
This will allow you to call the following:
#app/controllers/organizations_controller.rb
Class OrganizationsController < ApplicationController
def show
#organization = Organization.find params[:id]
#users_index = #organization.users
end
end
I'm implementing a classified website where I want to let user to create classified even if he is not registered. In case he is not registered I take his name, email and phone number. Its like those form on website where one can still create record without registering by only giving his email and name because asking new user to create account would turn away potential customers I am using devise and rails 4 and was wondering how can I implement this ideally.
Class User < ActiveRecord::Base
has_many :classifieds
end
class Classified < ActiveRecord::Base
belongs_to :user
end
I'm wondering if I should create a guest user as an instance of User or need to create new model to store classified poster that is not registered.
How you do this will depend mainly on how you're going to implement the user authentication
I see you've got devise as a tag - so I'll give you some ideas for it!
--
Devise
Devise has a helper called user_signed_in? - basically tells you if your current_user object is defined (and thus that your user is logged in).
In views, you can use this helper to determine how things work. A good example is in navigation:
#app/views/elements/nav.html.erb
<% if user_signed_in? %>
<%= link_to "Logout", user_session_destroy_path, method: :delete %>
<% else %>
<%= link_to "Login", new_user_session_path %>
<% end %>
In the same way, you can use the conditional nature of user_signed_in? for your form
--
Form
You'll basically need to ensure that you're able to process the form regardless of whether the user is signed in or not (I.E handle the credentials), but you could also use a conditional statement to determine which attributes to use:
<%= form_for #classified do |f| $>
<%= f.text_field :title %>
<%= f.text_field :description %>
<% if user_signed_in? %>
<%= f.fields_for :user do |user| %>
<%= user.text_field :name %>
<%= user.text_field :email %>
<%= user.text_field :phone_number %>
<% end %>
<% end %>
<% end %>
--
Controller
When you get the controller, you'll then need to consider whether the data has been submitted as form data or not. This is where user_signed_in? will again come in handy:
#app/controllers/classifieds_controller.rb
Class ClassifiedsController < ApplicationController
def new
#classified = Classified.new
#classified.build_user unless user_signed_in?
end
def create
#classified = Classified.new(classified_params)
#classified.user = current_user if user_signed_in?
end
private
def classified_params
params.require(:classified).permit(:title, :body, user_attributes(:name, :email, :phone)
end
end
What you can do is inside your create method for classifieds, you can look for a user and if he/she doesn't exist then create a dummy user with some random password and build classifieds for that dummy user. This will also keep your associations intact. Inside your create method you can do something like this:
def create
#user = User.find(params[:user_id])
if !#user
#user = User.create(attributes = {}, ...)
end
#classified = #user.classifieds.build(attributes = {}, ...)
if #classified.save
redirect_to your_path
else
render action: "new"
end
end
You can clean it more by using rails find_or_create_by method
I ran through railscast #37 and can't seem to even get my search form to display on my index page. Any ideas whats wrong with my code? thanks in advance! any help is greatly appreciated.
Here is the index page where the form is located:
<h1>All users</h1>
<% form_tag users_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
Heres the controller:
class UsersController < ApplicationController
...
def index
#title = "All users"
#users = User.paginate(:page => params[:page])
#usersearch = User.search(params[:search])
end
...
Lastly, the user.rb file:
...
def self.search(search)
if search
where('name LIKE ?', "%#{search}%")
else
all
end
end
I didn't look further, but there must be an equal sign in form_tag in the recent Rails versions. You should also get an error message on that in development mode.
Try <%= form_tag users_path, :method => 'get' do %>
I saw your previous question. It was deleted while I was submitting my answer. This looks similar to that question, so here is my answer to the previous question and this one.
I searched the users based on their country. So this is what I did for that:
First I created a new column country based on what I'm going to search. The command is
$ rails generate migration add_country_to_users country:string
$ rake db:migrate
Add this string to the attr_accessible in the user model as follows:
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation, :country
validates_presence_of :country
..........
attr_accessible lets you do a mass assignment. Don't forget to add the new column here.
Once this is done you are now ready to write a controller function. I named mine network because I want to display users based on country. My search word is going to be country and I will display all the users belonging to one particular country. The function definition is as follows:
class UsersController < ApplicationController
def network
#title = "All users"
#users = User.find_all_by_country(User.find(params[:id]).country)
end
end
For your question if you want to display users by name make it
User.find_all_by_name(User.find(params[:id]).name)
or something like that based on our search word.
Now coming to the display. I created a new page under views/users/ as network.html.erb as I want to display a network of users belonging to a country. First have one form from where you will give the input, i.e where you invoke the search. For mine I have a link in the header of my form. The link is as follows:
<li><%= link_to "Network", network_user_path(current_user) %></li>
Once user clicks this the following form will be displayed:
<h1>All users</h1>
<ul class="users">
<% #users.each do |user| %>
<li>
<%= gravatar_for user, :size => 30 %>
<%= link_to user.name, user %>
</li>
<% end %>
</ul>
So far, so good. Now the final step is to connect them by adding them in the routes.rb file. Add the following in that file:
MyApp::Application.routes.draw do
resources :users do
member do
get :following, :followers, :network, :news
end
end
end
So this is what I did for my application and it worked. I hope it helps.
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.