I'm using Devise timeoutable to time out user sessions, and am trying to use client-side AJAX calls to occasionally touch the user session and keep the session alive. However, the server-side call in my subclass of Devise::SessionsController is not actually "touching" the session and preventing timeout:
def touch
respond_to do |format|
format.html {head :bad_request}
format.js {
render :json => { :session_expires => User.timeout_in.to_i}, :status => :ok
}
format.json {
render :json => { :session_expires => User.timeout_in.to_i}, :status => :ok
}
end
end
What do I need to do to actually cause some session activity and prevent the timeout from triggering?
Related
We use below ruby and rails version -
Ruby 2.7.3 Rails 6.1.3.2
While creating a new user it throws the below error -
NoMethodError (undefined method `marshal_dump' for #ActiveModel::Errors:0x0000000006fcbba0 Did you mean? marshal_load):
app/controllers/user_controller.rb:33:in `create'
Below Create method defined in the controller -
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
I am making an app with a todo list and I recently tried to add the ability to build out the todo lists from the user.
I ran into a problem when I changed the following lines.
def new
#todo_list = current_user.todo_lists.build
end
def create
#todo_list = current_user.todo_lists(todo_list_params)
respond_to do |format|
if #todo_list.save
format.html { redirect_to #todo_list, notice: 'Todo list was successfully created.' }
format.json { render :show, status: :created, location: #todo_list }
else
format.html { render :new }
format.json { render json: #todo_list.errors, status: :unprocessable_entity }
end
end
end
I was using the following code.
def new
#todo_list = TodoList.new
end
def create
#todo_list = TodoList.new(todo_list_params)
respond_to do |format|
if #todo_list.save
format.html { redirect_to #todo_list, notice: 'Todo list was successfully created.' }
format.json { render :show, status: :created, location: #todo_list }
else
format.html { render :new }
format.json { render json: #todo_list.errors, status: :unprocessable_entity }
end
end
end
I have added a user id to the todo items by creating a new migration and migrated the data base and created an association to the user for the posts. Not really sure what's going wrong but any help would be greatly appreciated.
Thanks.
Change this line:
#todo_list = current_user.todo_lists(todo_list_params)
into this:
#todo_list = current_user.todo_lists.build(todo_list_params)
I am writing backend of an app in Rails. As I work on the backend, I need to give the frontend developer a REST API to start building the frontend. Eventually, the frontend and backend will reside together in a single app, but for now they are separate.
For time being I have enabled Cross-origin resource sharing in my app, by adding following to ApplicationController:
config.action_dispatch.default_headers.merge!({
'Access-Control-Allow-Origin' => '*',
'Access-Control-Request-Method' => '*'
});
For now, I have also turned off CSRF tokens by adding following to application.rb:
skip_before_filter :verify_authenticity_token
I am using Devise for authenticating users. To make Devise work with JSON requests, I have done following:
In devise.rb
config.navigational_formats = ['*/*', :html, :json]
In routes.rb
devise_for :users, :controllers => {:omniauth_callbacks => "omniauth_callbacks", :sessions => 'sessions', :registrations => 'registrations' }
My SessionsController
class SessionsController < Devise::SessionsController
#todo had to do following to support logging in through ajax. need to add logic to send back error response when login fails.
#todo see http://stackoverflow.com/questions/5973327/using-devise-1-3-to-authenticate-json-login-requests/8402035#8402035 and
#todo https://web.archive.org/web/20130928040249/http://jessehowarth.com/devise
#todo see http://stackoverflow.com/questions/11277300/devise-failure-authentication-via-json-sends-back-html-instead-of-json
def create
respond_to do |format|
format.html { super }
format.json {
resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure")
sign_in(resource_name, resource)
return render :json => {:success => true, :user => resource}
}
end
end
def destroy
respond_to do |format|
format.html { super }
format.json {
Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
render :json => {}
}
end
end
def failure
render :json => {:success => false, :errors => ["Login Failed"]}, :status => 422
end
end
I have a extended Devise's RegistrationsController as well as indicated in routes.rb, but am not posting its content here, as I don't think it is relevant to this question.
With the above setup I am able to send an ajax request to '/users/sign_in' with user[email] and user[password] parameters and have the user signed in. The response looks something like this:
{
success: true
user: {
authentication_token: "SNa2kPqkm5ENsZMx7yEi"
created_at: "2014-12-16T02:40:39.179Z"
email: "xyz#xyz.com"
id: 99999
name: null
provider: null
uid: null
updated_at: "2014-12-17T02:29:31.537Z"
}
}
Now how do I use the authentication_token I received in the sign_in response to send requests to other controller actions that require user to be authenticated? Do I need to set this token in a request header? I am not able to find information on how to use this token. Please help.
It seems following as described in the gist here, the answer is that you send the suer's email and authetication_token with every request to the backend. You may choose to send it in request header or simply as parameters. You simply modify the method that checks the email and token and signs in the user in ApplicationController accordingly. This is my ApplicationController (I am now sending the email and token as parameters in the request):
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
#todo remove this once ui is integrated. following turns off the csrf token:
skip_before_filter :verify_authenticity_token
#todo begin code to support authentication using token
# This is our new function that comes before Devise's one
before_filter :authenticate_user_from_token!
# This is Devise's authentication
before_filter :authenticate_user!
private
def authenticate_user_from_token!
user_email = params[:user_email].presence
user = user_email && User.find_by_email(user_email)
# Notice how we use Devise.secure_compare to compare the token
# in the database with the token given in the params, mitigating
# timing attacks.
if user && Devise.secure_compare(user.authentication_token, params[:user_token])
sign_in user, store: false
end
end
#todo end code to support authentication using token
end
I forgot to mention in my post that I had already added the migration to add a authentication_token column to User model. Also, I had to add following in the User model (as described in the gist), so that an authentication token is generated each time a user is created/updated:
#todo begin code to support ajax authentication of users
#todo see https://gist.github.com/josevalim/fb706b1e933ef01e4fb6
# You likely have this before callback set up for the token.
before_save :ensure_authentication_token
def ensure_authentication_token
if authentication_token.blank?
self.authentication_token = generate_authentication_token
end
end
private
def generate_authentication_token
loop do
token = Devise.friendly_token
break token unless User.where(authentication_token: token).first
end
end
#todo end code to support ajax authentication of users
I'm playing about with the Ruby Feedzirra gem and have managed to acheive what I set out to do by using it in the controller.
Though everything I've seen has mentioned using it in the model. I was just wondering if this is ok to do in the controller, if not, how might I go about achieving the same in the model?
I want to submit a Feed URL and use that to update my model with the rest of the information about the feed.
Feeds_controller.rb
def create
#feed = Feed.new(params[:feed])
feed = Feedzirra::Feed.fetch_and_parse(#feed.feed_url)
#feed.title = feed.title
#feed.url = feed.url
#feed.last_modified = feed.last_modified
respond_to do |format|
if #feed.save
format.html { redirect_to #feed, notice: 'Feed was successfully created.' }
format.json { render json: #feed, status: :created, location: #feed }
else
format.html { render action: "new" }
format.json { render json: #feed.errors, status: :unprocessable_entity }
end
end
end
feed.rb
class Feed < ActiveRecord::Base
attr_accessible :feed_url, :last_modified, :title, :url
end
I'd make an instance method on the Model and use that in the controller so
class Feed < ActiveRecord::Base
def fetch!
feed = Feedzirra::Feed.fetch_and_parse(feed_url) # probably want some eror handling here
title = feed.title
url = feed.url
last_modified = feed.last_modified
self #or nil if you like
end
end
then your controller thins down to
def create
#feed = Feed.new(params[:feed])
#feed.fetch!
respond_to do |format|
if #feed.save
format.html { redirect_to #feed, notice: 'Feed was successfully created.' }
format.json { render json: #feed, status: :created, location: #feed }
else
format.html { render action: "new" }
format.json { render json: #feed.errors, status: :unprocessable_entity }
end
end
end
The cool thing here is that if this gets too slow you can use something like Resque to run this in the background and just return a "your request is being processed" message to the user, then alert them asynchronously when the the request is done (might not work so well for the json request)
You really don't want to use something like a RSS parser in your controller. That will slow the responsiveness of that URL and your server.
Instead, run the RSS parser in a separate application, or at least a separate thread, and store the retrieved feeds in a database table for rapid access.
I have the following controller action:
def create
#board = Board.new(params[:board])
respond_to do |format|
if #board.save
set_board_session #board
set_new_board
format.js { render :action => "show" } #<== here I want to render html no js
else
format.js { render :action => "new" }
end
end
end
I want to render the show.html.erb action not the show.js.erb action for an ajax request.
How can I do this?
UPDATE
This seems to work for me:
I put this in my application controller:
def redirect_to(options = {}, response_status = {})
if request.xhr?
render(:show) {|page| page.redirect_to(options)}
else
super(options, response_status)
end
end
Now I can redirect with an Ajax call.
format.js {redirect_to #board}
Thanks to this forum:
Set dataType to "html" in your AJAX request and Rails will correctly handle AJAX request and render html, not js.
This seems to work for me:
I put this in my application controller:
def redirect_to(options = {}, response_status = {})
if request.xhr?
render(:show) {|page| page.redirect_to(options)}
else
super(options, response_status)
end
end
Now I can redirect with an Ajax call.
format.js {redirect_to #board}