Adding an editable field to omniauth generated / existing user - ruby-on-rails-4

I'm using omniauth-twitter to create and authenticate users in my rails app and I'm successfully getting everything I need from Twitter, avatar, username, description, etc. But I'd like to let users add a custom string to display on their account page.
I added a column to the User table and ran the migration. The column is there.
I can't seem to get the update form to work, however. I'm not seeing errors. I just get a page refresh. Since I didn't have an existing form or controller methods to begin with I added them manually.
Here's my Users controller (I'm using friendly-id, hope that doesn't throw you.)
class UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.friendly.find(params[:id])if params[:id]
end
def edit
#user = User.friendly.find(params[:id])if params[:id]
end
def update
#user = User.friendly.find(params[:id])if params[:id]
end
private
def user_params
params.require(:user).permit(:custom_text)
end
end
I'm not sure if I need both edit and update methods here, but I thought I'd try.
Here's my form (SLIM Template) which I include on the user's show page:
= form_for #user do |f|
= f.text_field :custom_text
= f.submit
The submit button works, as it were, but nothing is updated.
I'm pretty sure I'm just overlooking something painfully obvious.

I can't seem to get the update form to work, however. I'm not seeing errors.
Nothing is getting updated because you are not updating anything in the first place. As per the current code in the update action, its just selecting the record to be updated from the database but doing nothing with it.
def update
#user = User.friendly.find(params[:id])if params[:id] ## Simply selecting
end
In order to update the fetched record, you should call either update or update_attributes method on the instance of User model passing the changed attributes values to the method.
SOLUTION:
Use the following updated code in your UsersController. I have also DRYed up the code little bit by adding a before_action callback named set_user. The set_user method will be called every time before performing the actions such as show, edit and update and will take care of setting the instance variable #user.
class UsersController < ApplicationController
## Adding a before action callback
before_action :set_user, only: [:show, :edit, :update]
def index
#users = User.all
end
def show
end
def edit
end
def update
if #user.update(user_params)
## Redirect to user show page on successful update
redirect_to #user, notice: 'User was successfully updated.'
else
## Render user edit page again upon failure to update
render action: 'edit'
end
end
private
def set_user
#user = User.friendly.find(params[:id]) if params[:id]
end
def user_params
params.require(:user).permit(:custom_text)
end
end

Have you tried changing your form code to set the multipart:true to allow file to be sent
Try this and then upload the photo
= form_for #user,html: {multipart: true} do |f|
= f.file_field :custom_photo
= f.submit

I might also be missing something painfully obvious or new in Rails 4, but it seems like you should actually be telling the DB to update your record:
def update
#user = User.friendly.find(params[:id]) if params[:id]
#user.update_attributes(user_params) if #user
end
private
def user_params
params.require(:user).permit(:custom_text)
end
Without this second line in the update action, it's just finding the record and not doing anything with it...

Related

Devise not redirecting to specified page after User sign up

Problem: I am using the after_sign_up_path_for(resource) method provided by Devise but I cannot seem to get the User redirected to the specified page after they sign up. Currently I receive a Template Missing error with the url being www.localhost:3000/users. Ideally, I would like to have the User redirected to www.localhost:3000/subscribers/new
registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def create
#user = User.new(sign_up_params)
#domain = #user.email.split('#').last
#company = Company.find_by_domain(#domain)
#user.company_id = #company.id
if #user.save
after_sign_up_path_for(#user)
else
render 'new'
end
end
private
def sign_up_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :participation_code, :company_id)
end
protected
def after_sign_up_path_for(resource)
"/subscribers/new"
end
end
routes.rb
...
devise_for :users, controllers: { registrations: "registrations" }
...
Error Log I Get:
Template is Missing
Missing template registrations/create, devise/registrations/create,
devise/create, application/create with {:locale=>[:en], :formats=
[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby,
:coffee, :arb, :haml, :jbuilder]}.
UPDATE: I have tried moving the after_sign_up_path_for(resource) to the ApplicationController but still got the same result.
Very interesting. I simply changed
def create
...
end
to...
def update
...
end
Now everything works perfectly and my after_sign_up_path_for(resource) method is recognized.
Add below method in your application controller
Devise: Where to redirect users once they have logged in
def after_sign_up_path_for(resource)
"http://www.google.com" # <- Path you want to redirect the user to.
end
Maybe it worth to put redirect_method in after_action : create callback?
you dont need to create controller you can redirect user to specific path by defining
def after_sign_in_path_for(resource)
your_path
end
remember use after_sign_in_path_for not after_sign_up_path_for

Rails before filter not redirecting

Any reason why this before action would not redirect when #user is nil?
def set_user
#user ||= User.find(params[:id])
redirect_to "/errors/404" unless #user
end
I can actually see it redirecting in the log (pasted below).
Redirected to http://localhost:3000/errors/404
but instead of rendering that error page and routing away from the controller action, it completes the action and causes an error saying #user is nil.
The find method never returns nil. Instead, if a record with that ID doesn't exist, it throws an ActiveRecord::RecordNotFound error.
The easiest fix would be to use rescue_from:
class YourController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :redirect_to_not_found
# Other code
private
def set_user
#user ||= User.find(params[:id])
end
def redirect_to_not_found
redirect_to "/errors/404"
end
end
Now, the redirect_to_not_found method will be called whenever a user isn't found.

Only allow a user to edit their own content

I am using RoR 4 and the Devise gem for user authentication. I want a user to be able to edit their own content and not anyone else's content. The authenticate_user method only seems to make sure the user is logged in before they can edit the content. But another user can just sign up and edit everyone else's content.
My controller looks like:
class PrayersController < ApplicationController
before_action :find_prayer, only: [:show, :edit, :updated, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#prayers = Prayer.all.order("created_at DESC")
end
def show
end
def new
#prayer = current_user.prayers.build
end
def edit
end
def create
#prayer = current_user.prayers.build(prayer_params)
if #prayer.save
redirect_to #prayer, notice: "Successfully created prayer"
else
render 'new'
end
end
def update
#prayer = Prayer.find_by_id(params[:id])
if #prayer.update(prayer_params)
redirect_to #prayer, notice: "Prayer was successfully updated"
else
render 'edit'
end
end
def destroy
#prayer.destroy
redirect_to root_path
end
private
def prayer_params
params.require(:prayer).permit(:title, :body)
end
def find_prayer
#prayer = Prayer.find(params[:id])
end
end
I tried to make a before_action of my own that looked something like this:
def own_prayer
if !current_user == Prayer.current_user
redirect_to #prayer, notice: "You cannot edit this prayer"
end
end
But that did not work. I can limit access to the form via the view with a similar action but I don't think this is entirely safe?
Thank you
I guess you don't have class method current_user on Prayer class. Also seems you have has_many :prayers in your User model. So to get prayer's user you need to call user method on Prayer instance variable.
It's supposed to be like that:
#prayer = Prayer.find params[:id]
unless current_user == #prayer.user
redirect_to(#prayer, notice: "You cannot edit this prayer") and return
end
If you need more tricky restriction rules then use cancan gem

Rendering Partials Error Rails 4

I'm following a tutorial to create a follow feature for users. The tutorial creates separate links to view the users' followers and following. I, however, would like for these to be displayed on the user's profile page and not redirected to another page.
I thought I could accomplish this with a partial so I created _show_follow.html.erb in the user view with this simple code:
<h3><%= #title %></h3>
I tried to render it with this code in my user show view:
<%= render 'show_follow' %>
This does not work. I tested it with static code which works fine, so I'm assuming my problem is in the User controller:
class UsersController < ApplicationController
before_action :logged_in_user, only: [:edit, :update,
:following, :followers]
def show
#user = User.find(params[:id])
end
def following
#title = "Following"
#user = User.find(params[:id])
#users = #user.following.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
Can someone please guide me on the best/least sloppy way to accomplish this? I'm stuck. Thanks a million!

Devise show User

Despite all the questions and solutions I've read so far, nothing has worked for me yet here showing a signed in user profile page with devise. I've tried a number of things in my routes as well. My error is currently shows - "Couldn't find User without an ID". I'm a newbie with devise so while I like it, it has been a bit frustrating. Any help would be appreciated. Still very much in the learning stages. Thanks.
class UsersController < ApplicationController
before_filter :authenticate_user!, :except => [:show]
after_action :verify_authorized
def index
#users = User.all
authorize User
end
def show
#user = User.find(params[:id])
authorize #user
end
Routes
Rails.application.routes.draw do
devise_for :users
devise_scope :user do
get 'users/sign_in' => 'devise/sessions#new'
get 'users/sign_out' => 'devise/sessions#destroy'
end
resources :user
match 'users/show', to: 'users#show', via: 'get'
root to: 'pages#home'
end
match 'users/show', to: 'users#show', via: 'get'
This line suggests that it will route the url users/show to your controller#action users#show. And inside your controller you are looking for the user with the id of params[:id]. Except, you are never passing in an id parameter. Typically, the id is passed in the url (ie users/show/:id). That is the cause of your error.
The solution depends on what you are trying to accomplish. You could either pass the id through the url, or if you want the users/show to show only the logged in user profile, I would add a controller action (called profile for example) and then set/get a session variable with the user id and redirect to user's view.