Routing Issue Within Devise Users - ruby-on-rails

I am fairly new to Rails and am using Devise for user authentication in a new demo app. I have got Devise to work, along with the confirmable module and email verification.
I am now trying to build a phone verification on top of this. I updated the User model to have three additional fields: phone_number, phone_verified (boolean) and phone_verification_code. I also updated the Registrations Controller to allow the additional field of phone_number by the User model.
Now, in order to set up a phone verification system, I have created a page /user/:id/verify by adding a verify method in UsersController and updating the routes.rb. When I type in the URL, http://localhost:3000/users/10/verify, I see the view for that page.
However, I am trying to get to the view by creating a button on the /app/views/users/show.html.erb and my code below is getting an error. I am trying to get the correct path helper for the button. Can someone please help.
Here is the error:
Showing /home/ubuntu/work/depot/app/views/users/show.html.erb where line #10 raised:
undefined method `verify_user_path' for #<#:0x007fc3740fe3a0>
app/views/users/show.html.erb
<p id="notice"><%= notice %></p>
<div class="row">
<div class="col-md-offset-2 col-md-8">
<div class="panel panel-default">
<div class="panel-heading"><%= #user.email %></div>
<div class="panel-body">
<strong>Phone number: </strong><%= #user.phone_number %><br/>
<% if #user.phone_verified == nil %>
<%= button_to [:verify, #user] do %>
Verify Phone <strong><%= #user.phone_number %></strong>
<% end %>
<% else %>
<strong>Phone Verified: </strong><%= #user.phone_verified %><br/>
<% end%>
</div>
</div>
</div>
</div>
</div>
UsersController
class UsersController < ApplicationController
def index
#users = User.all
end
def show
begin
#user = User.find(params[:id])
rescue ActiveRecord::RecordNotFound
logger.error "Attempt to access an invalid user: #{params[:id]}"
redirect_to store_url, notice: "Attempt to access an invalid user: #{params[:id]}"
else
respond_to do |format|
format.html # show html.erb
format.json { render json: #user }
end
end
end
def verify
end
def generate_pin
#user.phone_verification_code = rand(0000..9999).to_s.rjust(4, "0")
save
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
rescue ActiveRecord::RecordNotFound
#user = nil
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params[:user]
end
end
routes.rb
Rails.application.routes.draw do
devise_for :users, controllers: { registrations: "registrations" }
resources :users, only: [:index, :show, :edit, :update]
resources :orders
resources :line_items
resources :carts
match "users/:id/verify" => "users#verify", via: [:get]
get 'store/index'
resources :products
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
# root 'welcome#index'
root 'store#index', as: 'store'

You need to use the as option in your route:
match "users/:id/verify" => "users#verify", via: [:get], as: 'verify_user'
Then restart your server. This will tell Rails to create the proper URL helper methods: verify_user_path and verify_user_url

match "users/:id/verify" => "users#verify", as: 'verify_user', via: [:get]
Or better way:
resources :users, only: [:index, :show, :edit, :update] do
get :verify
end

Related

Rails editing model from different controller

I have a Articles controller with corresponding Article Model.
I also have a different controller called Reviews.
They are not related or associated.
I am attempting to edit Article posts from reviews controller, but not able to do.
class ReviewsController < ApplicationController
def index
#article = Article.all
end
def show
#article = Article.find(params[:id])
end
def edit
#article = Article.find(params[:id])
end
def update
raise params.inspect
# #article = Article.find(params[:id])
# if #article.update_attributes(article_params)
# # Handle a successful update.
# else
# render 'edit'
# end
end
private
def article_params
params.require(:article).permit(:title, :body, :url,
:tags, :news_date, :status)
end
end
reviews/edit.html.erb
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_tag review_path(#article), method: "put" do %>
<label>Article title:</label><br>
<%= text_field_tag :title, #article.title %><br>
<label>Article Description</label><br>
<%= text_area_tag :body, #article.body %><br>
<%= submit_tag "Submit Post" %>
<% end %>
</div>
</div>
On submit action, why is it sending a POST request when I am specifically asking to set the form method to PUT?
routes.rb
resources :reviews, only: [:index, :show, :edit, :update]
scope module: 'api' do
namespace :v1 do
resources :articles, only: [:index, :show]
end
end
>$ bundle exec rake routes
Prefix Verb URI Pattern Controller#Action
reviews GET /reviews(.:format) reviews#index
edit_review GET /reviews/:id/edit(.:format) reviews#edit
review GET /reviews/:id(.:format) reviews#show
PATCH /reviews/:id(.:format) reviews#update
PUT /reviews/:id(.:format) reviews#update
v1_articles GET /v1/articles(.:format) api/v1/articles#index
v1_article GET /v1/articles/:id(.:format) api/v1/articles#show
You can find the answer here:
https://apidock.com/rails/ActionView/Helpers/FormTagHelper/form_tag
":method - The method to use when submitting the form, usually either “get” or “post”. If “patch”, “put”, “delete”, or another verb is used, a hidden input with name _method is added to simulate the verb over post."

(undefined method `receipts_for' for nil:NilClass - MailBoxer Gem Rails

I'm using the mailboxer gem to build a messaging system between users for my rails application. For some reason, I'm getting this error:
(undefined method `receipts_for' for nil:NilClass)
Maybe it's because I should define 'receipts_for' somewhere in my controller or in the mailboxer.rb? I tried a few things.. but unfortunately none of them were successful.
This is my routes.rb:
Rails.application.routes.draw do
root 'static_pages#home'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new'
get '/login', to: 'sessions#new'
get 'search/index'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
resources :users do
member do
get :following, :followers
end
end
resources :conversations do
resources :messages
end
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
resources :microposts, only: [:create, :destroy]
resources :relationships, only: [:create, :destroy]
resources :searches
end
This is my conversations controller:
class ConversationsController < ApplicationController
def show
#conversation = current_user.mailbox.conversation.find(params[:id])
end
def new
#recipients = User.find(params[:user_id])
end
def create
recipient = User.find(params[:user_id])
receipt = current_user.send_message(recipient, params[:body])
redirect_to conversation_path(receipt.conversation)
end
end
This is my messages_controller:
class MessagesController < ApplicationController
before_action :set_conversation
def create
receipt = current_user.send_message(#conversation, body)
redirect_to receipt.conversation
end
private
def set_conversation
#conversation = current_user.mailbox.conversations.find(params[:conversation_id])
end
end
The messaging system I'm building precisely, is a messaging system where the 'current_user' can go to the profile page of any user on the application and message him/her via the profile page. So this means that I'm rendering show.html.erb of the conversation model inside the show.html.erb of my users model. Here is the code of both views:
show.html.erb - Users Model:
<% provide(:title, #user.name) %>
<div class="row">
<aside class="col-md-4">
<section>
<h1>
<%= gravatar_for #user %>
<%= #user.name %>
</h1>
</section>
<section class="stats">
<%= render 'shared/stats' %>
</section>
<h6>
<%= #user.gender %>
</h6>
<%= render "conversations/conversation" %>
</aside>
<div class="col-md-8">
<%= render 'follow_form' if logged_in? %>
<% if #user.microposts.any? %>
<h3>Microposts (<%= #user.microposts.count %>)</h3>
<ol class="microposts">
<%= render #microposts %>
</ol>
<%= will_paginate #microposts %>
<% end %>
</div>
</div>
_conversation.html.erb - show view of the conversations model.
<% #conversation.receipts_for(current_user).each do |receipt| %>
<div>
<%= receipt.message.body %>
</div>
<% end %>
<%= form_tag conversation_messages_path(#conversation), method: post do %>
<div>
<%= text_area_tag :body %>
</div>
<%= submit_tag %>
<% end %>
So how exactly can I define the 'receipts_for' method for my mailboxer? Or is something else wrong with my code?
Any help would be much appreciated!
Thanks!
I’ll piggy-back on what #mu is too short said. It’s important to pay attention to the whole error message. “undefined method receipts_for for nil:NilClass” is telling you that the receiver of the receipts_for method is nil. #conversation.receipts_for(current_user) looks to be the only place where receipts_for is used, so I would start debugging by making sure #conversation is assigned the value of an existing ActiveRecord-backed conversation object.
There seems to be too a lot going on, so I don't know how to offer you a quick fix. The value assignment in your ConversationsController#show method, #conversation= current_user.mailbox.conversation.find(params[:id]) looks cumbersome. That suggests to me that you're looking for a conversation based on a mailbox belonging to the current_user, which might be what you want (in which case, you need to have the appropriate associations defined in your models).
However, since the chain ends with conversation.find(params[:id]), I'm guessing that current_user.mailbox is not needed. Alternatively, if your params don't actually have a conversation id, then maybe that's what you need to focus on.
The good news is you can probably figure out how to define #conversation if you stick byebug (or binding.pry, depending on what you have installed) at the top of your show method and in your view partial:
# In the controller:
def show
binding.pry
#conversation = current_user.mailbox.conversation.find(params[:id])
end
# in the view
<% binding.pry %>

Allow users to edit their profile fields in rails 4

I have a new question.
What I want to do?
I've created the profile for each player, now I want to allow users to edit their profile.
Part of this profile takes the devise table, with a second table called profiles.
Devise: Captures username, password and email
Profiles: Captures Personal Information
Schema of Profiles
create_table "profiles", force: :cascade do |t|
t.text "about"
t.string "fb"
t.string "skype"
t.string "birthday"
t.string "twitter"
t.string "steam"
t.string "gender"
t.string "occupation"
t.string "location"
t.string "interest"
end
My profile_controller.rb (Updated)
class ProfileController < ApplicationController
def index
#profile = Player.all
end
def show
#profile = Player.find_by(nick: params[:nick])
end
def edit
# use this to populate a form in your view
#profile = Player.find_by(nick: params[:nick])
end
def update
#profile = Player.find_by(nick: params[:nick])
if #profile.update_attributes(profiles_params)
redirect_to(:action => "show", :profile => #profile.nick)
else
render("index")
end
end
private
def profiles_params
params.require(:profiles).permit(:about, :skype)
end
end
Rake routes
profiles GET /profiles(.:format) profiles#index
GET /profiles/:nick/edit(.:format) profiles#edit
GET /profiles/:nick(.:format) profiles#show
PATCH /profiles/:nick(.:format) profiles#update
PUT /profiles/:nick(.:format) profiles#update
Routes.rb
devise_for :players
resources :profile, param: :nick
resources :profiles, only: [:index, :show, :edit, :update], param: :nick
Notes:
I have a profile controller
I have these pages:
show.html.erb
index.html.erb
Now my question is:
*How should I make the edit page for each users profile,
considering that each user edits their own profile?
Once a user edits a field, I want this to be reflected on the page show.html.erb. How can I achieve this?*
** show.html.erb **
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="info">
<p><div class="form-group">
<label for="textArea" class="col-lg-2 control-label">About <%= #profile.nick %></label>
<div class="col-lg-10">
<pre style="padding-bottom: 200px;"><%= #profiles.about %>(THIS IS THE ERROR)</pre>
<span class="help-block">In Progress</span>
</div>
</div></p>
</div>
** edit.html.erb (Not _edit, because missing template)**
<strong>Testing About</strong>
<%= form_for :profiles do |f| %>
<%= f.label :about %>
<%= f.text_field :about %>
<div class="btn btn-primary">
<a href="http://localhost:3000/profile/<%= #profile.nick %>">
<%= f.submit "Update Profile", :class => 'btn btn-primary' %></a>
</div>
<% end %>
<% end %>
<p>I am editing for</p>
<%= #profile.nick %>
Thanks in advance
Show should be used to display a users profile, not edit it - this is the rails way.
I suggest you jump over and have a read on rails resourceful routing: http://guides.rubyonrails.org/routing.html - this covers routes and CRUD.
Consider you have your resource, :profiles - in your routes this can be declared as:
resources :profiles
This route will automatically create the desired routes for you - in this case we only seem to want index, show, edit and update therefore this can be declared:
resources :profiles, only: [:index, :show, :edit, :update]
We now have the following routes, i've commented what their purpose should be:
GET /profiles #show all profiles
GET /profiles/:id #show specific user profile
GET /profiles/:id/edit #edit specific user profile
PATCH /profiles/:id #update a specific profile
Now that we have our routes lets look at this from a controller perspective - i'm jsut going to focus on edit/update as this is your question:
class ProfileController < ApplicationController
def index
#do something
end
def show
# do something
end
def edit
# use this to populate a form in your view
#profile = get_profile
end
def update
#profile = get_profile
if #profile.update_attributes(profile_params)
#do something on success
else
# do something on fail
end
end
private
def profile_params
params.require(:profile).permit(:about, :skype, etc)
end
def get_profile
nick = params[:nick]
if Player.where(username: nick).present?
if Player.where(username: nick).count == 1
Player.includes(:profile).find_by(username: nick).profile
else
raise "Error: Multiple profiles found"
end
else
raise "Error: Profile cannot be found"
end
end
end
You'll notice the 'profile_params' method, this is apart of rails strong paramaters and whitelists the attributes we can use for mass assignment. Read more: http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html
Because our routes are set up as expected for our profile, our forms are super simple as rails can infer everything.
edit.html.erb
<%= form_for #profile do |f| %>
<%= f.text_field :about %>
... etc
<% f.submit %> # this will submit to profile#update
<% end %>
Further reading on form_for: http://apidock.com/rails/ActionView/Helpers/FormHelper/form_for
Ofcourse you should also be adding authorisation to the controller methods but hopefully i've covered the basic premise for you.
EDIT1: In regards to your comment I've added a private method for locating your user profile by either username or id (tweak to suit). But like I said, go through the linked readings so you can get an understanding of routing.
EDIT2: SO taking into consideration your further comments and the routes you added to the question i've updated your get_profile method.

undefined method `each' for nil:NilClass within Pages#friends

I am trying to get my followers to display on the pages/friends however, I keep getting multiple errors like an undefined method `each' for nil:NilClass in my Pages#friends error. I am following Michael Harlts tutorials on follow/unfollow however, I needed to tweak a couple of things because I did not follow the entire thing.
When a user goes to their Friends link (pages/friends) I want it to display everyone who is following them. Like how my users/index displays everyone. Please see my code below. Any help of suggestions would be great.
Pages/friends
<h1>Friends</h1>
<% #user ||= current_user %>
<% #users.each do |user| %>
<center><%= link_to image_tag(user.avatar.url(:thumb)), user %></center>
<strong><center><br><%= link_to user.name, user %></br></center></strong>
<% if current_user.admin %>
<% end %>
<% end %>
Pages/controller
def home
end
def about
end
def friends
end
end
**Users/index*
<% provide(:title, 'All users') %>
<h1>All users</h1>
<div class="col-md-offset-4 col-med-8">
<div class="panel panel-default">
<div class="panel-heading center">
<% #users.each do |user| %>
<center><%= link_to image_tag(user.avatar.url(:thumb)), user %></center>
<strong><center><br><%= link_to user.name, user %></br></center></strong>
<% if current_user.admin %>
<% #user ||= current_user %>
<div class="stats">
<a href="<%= friends_path(#user) %>">
<strong id="following" class="stat">
<%= #user.followed_users.count %>
</strong>
following
</a>
<a href="<%= friends_path(#user) %>">
<strong id="followers" class="stat">
<%= #user.followers.count %>
</strong>
followers
</a>
</div>
<center><%= link_to "Delete", user, method: :delete, data: { confirm: "Are you sure?" } %></center>
<% end %>
<% end %>
<div class="center">
<%= will_paginate #users, renderer: BootstrapPagination::Rails %>
</div>
</div>
Routes
devise_for :admins
devise_for :users
resources :posts
resources :users do
member do
get :following, :followers
end
end
resources :relationships, only: [:create, :destroy]
resources :user_friendships do
member do
put :accept
end
end
get "users/show"
root "pages#home"
get 'feed', to: 'posts#index', as: :feed
get "about" => "pages#about"
get "friends" => 'pages#friends'
match 'users/:id' => 'users#show', via: :get
match 'users/:id' => 'users#index', via: :destroy
match 'users/:id' => 'users#destroy', via: :get
match 'users/:id' => 'users#destroy', via: :delete
get '/:id', to: 'users#show'
Users/controller
class UsersController < ApplicationController
before_action :correct_user, only: [:edit, :update, :destroy, :following, :followers]
before_action :authenticate_user!, except: [:index, :show]
before_action :admin_user, only: :destroy
def index
#users = User.paginate(page: params[:page], :per_page => 5)
end
def show
#user = User.find(params[:id])
if #user
#posts = #user.posts.all
render actions: :show
else
render file: 'public/404', status: 404, formats: [:html]
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "Your account has been deleted."
redirect_to root_path
end
def correct_user
#user = User.find(params[:id])
redirect_to root_path
end
def admin_user
redirect_to root_path unless current_user.admin?
end
def following
#title = "Following"
#user = User.find(params[:id])
#users = #user.followed_users.paginate(page: params[:page])
render 'show_follow'
end
def followers
#title = "Followers"
#user = User.find(params[:id])
#users = #user.followers.paginate(page: params[:page])
render 'show_follow'
end
end
end
Relationships Controller
class RelationshipsController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
def create
#user = User.find(params[:relationship][:followed_id])
current_user.follow!(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
def destroy
#user = Relationship.find(params[:id]).followed
current_user.unfollow!(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
end
The error undefined method 'each' for nil:NilClass means that you're calling .each on an object that is nil.
For example, here, #users could be nil:
def index
#users = User.paginate(page: params[:page], :per_page => 5)
end
If you then call <% #users.each ... %>, you'll get the undefined method error. You've posted quite a lot of code above, so it's difficult to know exactly where that error is being thrown. Try and work out exactly where the error is being thrown (posting a stack trace would help), and work out which object is nil. Then work out why it's nil - is there no data? Or is your ActiveRecord query returning no results?
Hopefully that gives you some pointers as to where to start looking next.
Edit: As mmichael points out, the error is being caused due to the fact that #users was undeclared in pages#friends. Thanks!
As you're new, I'll give you another opinion. What I'm going to write is similar to Sam's answer; I intend to help you appreciate how Rails works, to further your experience
Objects
You must remember that Rails is built on top of Ruby - an object-orientated language. This means every time you declare / use a variable inside Ruby, you're actually accessing an object, which Ruby treats as having a series of methods:
Ruby is pure object-oriented language and everything appears to Ruby
as an object. Every value in Ruby is an object, even the most
primitive things: strings, numbers and even true and false. Even a
class itself is an object that is an instance of the Class class. This
chapter will take you through all the major functionalities related to
Object Oriented Ruby.
I write this because Ruby's object-orientated structure is much different than handling variables in the "traditional" sense -- in the simplest description, it means that Ruby presumes that objects are ALWAYS present (it just builds them from the NilClass), allowing you call "empty" data sets without running into "undeclared" issues
The problems occur when you try and run methods like .each on empty / nil objects. If you do this, errors like the one you alluded to occur; preventing you from being able to perform the functionality which you intended
--
Fix
Your error basically means you haven't declared your variable.
After seeing your code, the most obvious problem will be here:
#app/controllers/pages_controller.rb
Class PagesController < ApplicationController
def friends
# normally, you'd define your #instance_variables here
end
end
I see that your friends action does not declare your #users variable, which is required to perform the #users.each method. As recommended by Sam, the first step is to ensure you're able to declare this value, allowing you to loop through it as required:
#app/controllers/pages_controller.rb
Class PagesController < ApplicationController
def friends
#users = User.all
end
end

Couldn't find User without an ID

Using Rspec/Device/Cucumber template app
Upon logging in I wish the user to be redirected to the users#index
my routes file
Engage::Application.routes.draw do
authenticated :user do
root to: 'users#show'
end
root :to => "home#index"
devise_for :users
resources :users, only: [:index]
resources :agendas, only: [:create, :destroy]
end
Upon logging in I get a error
ActiveRecord::RecordNotFound in UsersController#show
Couldn't find User without an ID
My users_controller
class UsersController < ApplicationController
before_filter :authenticate_user!
def index
#user = current_user
#agendas = #user.agendas
end
end
I've tried adding "#user = User.find(params[:id])" instead of using the current_user helper method but i'm still having issues
my show view in my users folder under views is
<div class="row">
<div class="span8">
<% if #user.agendas.any? %>
<h2>Agendas (<%= #user.agendas.count %>)</h2>
<ol class="agendas">
<%= render #agendas %>
</ol>
<% end %>
</div>
</div>
To redirect user after log in, did you see this help :
https://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-on-successful-sign-in-out

Resources