I am a rookie in Rails. I am using Rails 4 and I could not find how they do this or what it is called.
I got this idea from devise where you can use devise and implement such thing in your application.html.erb file:
<% if user_signed_in? %>
Logged in as <strong><%= current_user.email %></strong>.
Where user is the devise model.
However when I try to search for user_signed_in or current_user variable, I cannot find it at all!
So essentially what I want to do is link this user model (which is used for devise) with another model that I created called profile. These models are linked by their ids, and if user has not created a profile, then simply ask user to create his/her profile.
To do that, I've written this to application.html.erb:
<% if user_signed_in? && (current_profile.id != current_user.id)? %>
<%= link_to 'You have not created your profile! Please create your profile first.', update_profile_index_path, :class => 'navbar-link' %>
<% else %>
<%= yield %>
<% end %>
Which does not work as expected because I have not defined current_profile. The error that I am getting is:
undefined local variable or method `current_profile' for #<#<Class:0x000000044d6c60>:0x00000005d64110>
My question is, how do I create a variable named current_profile that would contain the current profile, like current_user that devise does?
The usual setup for this is to add a Profile model with a user_id:integer field.
Define an assocition on the User model
has_one :profile
Then you can access it directly using
current_user.profile
You can do the following:
class User
has_one :profile
# ...
class Profile
belongs_to :user
# ...
module ApplicationHelper # app/helpers/application_helper.rb
def current_profile
#current_profile ||= current_user.try(:profile)
#current_profile
end
# ...
# view
<% if user_signed_in? && current_profile.blank? %>
<%= link_to 'You have not created your profile! Please create your profile first.', update_profile_index_path, :class => 'navbar-link' %>
<% else %>
<%= yield %>
<% end %>
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
This is the method I would like to access in my views:
def current_user?(user)
user == current_user
end
I essentially need to check that the current user can not friend and unfriend themselves in the view.
<% unless current_user?(#user) %>
<% if current_user.friendly?(#user)
<%= render 'unfriend' %>
<% else %>
<%= render 'friend' %>
<% end %>
<% end %>
The current_user helper method is already provided by Devise.
How and where do I add this method in my Rails project?
Thanks for your help
To use application helper method in devise views.
Place your class_eval code at the bottom of Devise initializer, Just after the Devise.setup block.
config/initializers/devise.rb
Devise.setup do |config|
# ... existing Devise configuration, no modification necessary to include helper(s) ...
end
EDIT:
Devise::Mailer.class_eval do
helper :application # include "ApplicationHelper", adjust to suit your needs
end
In my opinion you could simple add the comparison on the view like this:
<% if current_user != #user %>
<% if current_user.friendly?(#user)
<%= render 'unfriend' %>
<% else %>
<%= render 'friend' %>
<% end %>
<% end %>
Anyway if you still want to use the method you could create a method in User.rb
def equal_user?(another_user)
another_user == self
end
and in the view
<% if #user.equal_user?(current_user) %>
I made a mistake initially in the application_helper.rb file.
I used an instance variable current_user?(#user) instead of the local variable current_user?(user).
If I was not using Devise I would have put the helper method in the sessions helper. So i figured it would work in the appication helper but was not positive.
Thanks #JesseWolgamott
I have post and user model and I have Many(posts) to One(User) association.
I want to display only the posts which are created by that user(current user).
So somehow I have to inject the currently logged in user's id into the "user_id" foreign key
of the post model during creation. I'm using Devise as my authentication system.
Any solutions of how to achieve this ?
I'm using Rails version 3.0.
Thanks in advance.
With devise simply use the "current_user" helper ;)
<% if user_signed_in? %>
<% current_user.posts.each do |post| %>
<%= post.title %>
<% end %>
<% end %>
In your PostsController#create method, you can set the Post's user to the current_user (since you are using Devise).
def create
#post = Post.create(params[:post]) do |p|
p.user = current_user
end
#respond_with(#post) or Rails 2 equivalent
end