After installing devise and adding authentication & User model successfully, every time i try an sign up to my web app i can get to the sign in page and login but when i click submit i get NoMethodError in BookmarksController#index undefined method `page' for #
# GET /bookmarks
def index
error -> #bookmarks = current_user.bookmarks.order('created_at desc').page(params[:page])
end
# GET /bookmarks/1
bookmarks controller
class BookmarksController < ApplicationController
before_action :set_bookmark, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
# GET /bookmarks
def index
#bookmarks = current_user.bookmarks.order('created_at desc').page(params[:page])
end
# GET /bookmarks/1
def show
end
# GET /bookmarks/new
def new
#bookmark = current_user.bookmarks.new
end
# GET /bookmarks/1/edit
def edit
end
# POST /bookmarks
def create
#bookmark = current_user.bookmarks.new(bookmark_params)
if #bookmark.save
redirect_to #bookmark, notice: 'Bookmark was successfully created.'
else
render action: 'new'
end
end
# PATCH/PUT /bookmarks/1
def update
if #bookmark.update(bookmark_params)
redirect_to #bookmark, notice: 'Bookmark was successfully updated.'
else
render action: 'edit'
end
end
# DELETE /bookmarks/1
def destroy
#bookmark.destroy
redirect_to bookmarks_url, notice: 'Bookmark was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_bookmark
unless #bookmark = current_user.bookmarks.where(id: params[:id]).first
flash[:alert] = 'Bookmark not found.'
redirect_to root_url
end
end
# Only allow a trusted parameter "white list" through.
def bookmark_params
params.require(:bookmark).permit(:title, :url, :user_id)
end
end
bookmark.rb
class Bookmark < ActiveRecord::Base
belongs_to :user
end
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :bookmarks
end
Remove call for page method from index action:
def index
#bookmarks = current_user.bookmarks.order('created_at desc')
end
Its not defined anywhere in the given code in the question. page method is usually used with will_paginate gem and you are not using it, so remove the call.
Related
I am working with a rails 7 application and using devise for authentication.
I have a bookings controller which looks like this
class BookingsController < ApplicationController
before_action :set_booking, only: %i[show edit update destroy]
before_action :authenticate_user!
def index
#bookings = Booking.all
end
def show
end
def new
#booking = Booking.new
end
def create
#booking = Booking.new(booking_params)
respond_to do |format|
if #booking.save
format.html {redirect_to booking_url(#booking), notice: "Booking was successfully created"}
else
format.html {render :new, status: :unprocessable_entity}
end
end
end
def edit
end
def update
respond_to do |format|
if #booking.update(booking_params)
format.html {redirect_to booking_url(#booking), notice: "Booking was successfully updated"}
else
format.html {render :new, status: :unprocessable_entity}
end
end
end
def destroy
#booking.destroy
respond_to do |format|
format.html {redirect_to bookings_url, notice: "Booking was successfully destroyed"}
end
end
private
def booking_params
params.require(:booking).permit(:room_id, :start, :end, :purpose, :user_id)
end
def set_booking
#booking = Booking.find(params[:id])
end
end
User model which looks like this
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :bookings
end
When I am logged in, I am able to view and edit any user's content, however I want to restrict it so only user_id 1 can see booking belonging to user_id 2. Right now any user can edit any booking regardless of who the booking belongs to.
Thank you!
Best thing to do is alter the below private method :
def set_booking
#booking = current_user.bookings.find(params[:id])
end
and also your index method :
def index
#bookings = current_user.bookings
end
And new and create too...
and move your authentication callback on top of callbacks.
Also as advised in the comments you can use gem Pundit in order to authorize properly in case you get more complex scenarios.
I'm new to Rails and I'm stuck at something really silly. I was trying to make an app where users can post pinterest-like pins, so I went with user has_many: pins and pin belongs_to: user. Here's the codes from a few files just to give you an idea of what state I'm in right now:
app/models/user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :pins
end
app/models/pin.rb
class Pin < ActiveRecord::Base
belongs_to :user
end
pins_controller.rb
class PinsController < ApplicationController
before_action :find_pin, only: [:show, :edit, :update, :destroy]
def index
#pins = Pin.all.order("created_at DESC")
end
def show
end
def new
#pin = current_user.pins.build
end
def create
#pin = current_user.pins.build(pin_params)
if #pin.save
redirect_to #pin, notice: "Successfully created new Pin"
else
render 'new'
end
end
def edit
end
def update
if #pin.update(pin_params)
redirect_to #pin, notice: "Pin was successfully updated!"
else
render 'edit'
end
end
def destroy
#pin.destroy
redirect_to root_path
end
def error
end
private
def pin_params
params.require(:pin).permit(:title, :description)
end
def find_pin
#pin = Pin.find(params[:id])
end
end
/views/pins/show.html.haml
%h1= #pin.title
%p= #pin.description
%p
%hr
%strong Submitted by
= #pin.user.email
Here, in the last line of show.html.haml, I want the #pin.user.email to be a link so that
the profile of the user (the one who submitted the article) can be accessed when clicked on it.
the profile of the user should list all of the articles submitted by him/her.
These are the two things that I'm trying to accomplish but don't know the code I should use for it. I don't have a users_controller. I did have one but I deleted it after it started messing with devise's routes. All answers are welcome, thanks in advance!
First Of All Create User Controller.
Redirect Show page line to user show action
Then you perform what you want.
For Ex.
link_to "User Profile", user_path(#pin.user.id)
users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find_by_id(params[:id])
#pins = #user.pins
end
end
/views/users/show.html.haml
User #user and #pins to Display What you want.
You forgot to define your show method
def show
#pin
end
having issues keep getting error undefined method `pins' for nil:NilClass, can someone explain how to fix this error. Been following a tutorial and recently got stuck.
pins_controller.rb
class PinsController < ApplicationController
before_action :find_pin, only: [:show, :edit, :update, :destroy]
def index
#pins = Pin.all.order("created_at DESC")
end
def new
#pin = current_user.pins.build
end
def create
#pin = current_user.pins.build(pin_params)
if #pin.save
redirect_to #pin, notice: "Successfully created new Pin"
else
render 'new'
end
end
def edit
end
def update
if #pin.update(pin_params)
redirect_to #pin, notice: "Pin was Successfully updated!"
else
render 'edit'
end
end
def destroy
#pin.destroy
redirect_to root_path
end
private
def pin_params
params.require(:pin).permit(:title, :description)
end
def find_pin
#pin = Pin.find(params[:id])
end
end
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :pins
end
pin.rb
class Pin < ActiveRecord::Base
belongs_to :user
end
routes.rb
Rails.application.routes.draw do
devise_for :users
resources :pins
root "pins#index"
end
If you are using the gem Devise then the helper method current_user returns you the current logged in user in your session.
Pleases make sure a user is logged in/
You can make sure that the user is logged in by adding before_action :authenitcate_user! in your application controller(for all actions in your application).
If you are using devise, you might want to add
before_action :authenitcate_user!
method inside pins controller which ensures that the user is logged in.
I am not sure that it is even related but since i added devise i am getting a no method error which reads as follows. undefined method `posts' for nil:NilClass
This is specifically directed at the following line of code.
#post = current_user.posts.build
I am rather stuck here as i have checked all the obvious and unless i remove the code so it reads
#post = Post.new
I am otherwise unable to add new posts. I have added the full code below.
Posts Controller
class PostsController < ApplicationController
before_action :find_post, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.all.order("created_at DESC")
end
def show
end
def new
#post = current_user.posts.build
end
def create
#post = current_user.posts.build(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
def edit
end
def update
if #post.update(post_params)
redirect_to #post
else
render 'edit'
end
end
def destroy
#post.destroy
redirect_to root_path
end
private
def find_post
#post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :content)
end
end
Post model`
class Post < ActiveRecord::Base
belongs_to :user
end
User model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :posts
end
new html haml
%h1 New Post
= render 'form'
The code looks ok...
But what happens if there is no user signed in?
try add
before_action :authenticate_user!
or ask
user_signed_in?
before you try to access the logged in user.
Need to see your how you have integrated your devise. But yes, maybe your not signed in that's why the nil error.
I am using Devise and am trying to allow each User to create 1 Profile. I am able to send the the newly registered User to the page where they can create a Profile, but once the User logs out and back in it will not go to the Profile Show page.
In other words-
I can sign up a new User and send the User to the Create Profile page, then I can create a Profile with the new User(I am not sure the Profile is saving correctly)... After I log out and sign in I recieved the error:
ActiveRecord::RecordNotFound in ProfilesController#show
Couldn't find Profile without an ID
I would like the User to be sent to their Profile Show page...
Any thoughts on the issue?
The code (sorted by files) is below…
user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me
has_one :profile
end
profile.rb
class Profile < ActiveRecord::Base
attr_accessible :first_name, :last_name
belongs_to :user
end
profiles_controller.rb
class ProfilesController < ApplicationController
# GET /profiles
# GET /profiles.json
def index
#profiles = Profile.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #profiles }
end
end
# GET /profiles/1
# GET /profiles/1.json
def show
#profile = Profile.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #profile }
end
end
# GET /profiles/new
# GET /profiles/new.json
def new
#profile = Profile.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #profile }
end
end
# GET /profiles/1/edit
def edit
#profile = Profile.find(params[:id])
end
# POST /profiles
# POST /profiles.json
def create
#profile = Profile.new(params[:profile])
respond_to do |format|
if #profile.save
format.html { redirect_to #profile, notice: 'Profile was successfully created.' }
format.json { render json: #profile, status: :created, location: #profile }
else
format.html { render action: "new" }
format.json { render json: #profile.errors, status: :unprocessable_entity }
end
end
end
# PUT /profiles/1
# PUT /profiles/1.json
def update
#profile = Profile.find(params[:id])
respond_to do |format|
if #profile.update_attributes(params[:profile])
format.html { redirect_to #profile, notice: 'Profile was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #profile.errors, status: :unprocessable_entity }
end
end
end
# DELETE /profiles/1
# DELETE /profiles/1.json
def destroy
#profile = Profile.find(params[:id])
#profile.destroy
respond_to do |format|
format.html { redirect_to profiles_url }
format.json { head :no_content }
end
end
end
registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
protected
def after_sign_up_path_for(resource)
request.env['omniauth.origin'] || stored_location_for(resource) || new_profile_path
end
end
application_controller.rb
class ApplicationController < ActionController::Base
def after_sign_in_path_for(resource)
request.env['omniauth.origin'] || stored_location_for(resource) || show_path(resource.profile)
end
end
routes.rb
BaseApp::Application.routes.draw do
resources :profiles
get "users/show"
devise_for :users, :controllers => { :registrations => "registrations" }
resources :users
match '/show', to: 'profiles#show'
match '/signup', to: 'users#new'
root to: 'static_pages#home'
match '/', to: 'static_pages#home'
…
end
In your controller you use the following code #profile = Profile.find(params[:id]). When signing in params[:id] must be nil.
It's not nil when you redirect after creating because you send in an id here redirect_to #profile. That translates to redirect_to profile_path(#profile). When you use the /match path there is no id.
So one solution would be to use the helper current_user in the ProfileController's show action. Replace #profile = Profile.find(params[:id]) with #profile = current_user.profile. That might change your desired functionality as it will require a user to be signed in. This will keep the math path (/show url). It works because it no long relies on an id.
You could alternatively change the show_path(resource.profile) to profile_path(resource.profile). That will use the resources profiles path with the url /profiles/:id instead of show/ you were possibly looking for.
With answer #Phil provide I solved another problem in my project. Thanks \o/
ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-linux]
Rails 4.0.0
And your case, I solved this way:
Add inverse_of: in user and profile model:
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :profile, inverse_of: :user
end
profile.rb
class Profile < ActiveRecord::Base
belongs_to :user, inverse_of: :profile
validates :first_name, :user_id, :presence => true
validates :gender, :inclusion => {:in => %w(M F)}
end
In your application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
# redirect user after login
def after_sign_in_path_for(resource)
unless current_user.profile.nil?
profiles_path
else
flash[:alert] = "Please complete your profile"
new_profile_path
end
end
# redirect after logout
def after_sign_out_path_for(resource_or_scope)
new_user_session_path
end
end
This works for me, I hope this helps