CSRF Error in Production: ActionController::InvalidCrossOriginRequest - ruby-on-rails

I am getting the following error on my comments controller in my production environments only (works fine in development). The user flow is as follows: I have jQuery that runs when a specific button is pushed which renders a partial file to add a new comment, a simple form. The respond_to method for the .js request in the controller is for new.js.erb file. This should be relatively easy to do but something is going wrong in the Rails (I am using Rails 4.1.1) code or on my server (Rackspace Cloud Server). The error is below:
ActionController::InvalidCrossOriginRequest in CommentsController#new
Security warning: an embedded tag on another site requested protected JavaScript. If you know what you're doing, go ahead and disable forgery protection on this action to permit cross-origin JavaScript embedding.
I have tried the following code in my comments controller (does not work). It simply renders the .js file in the browser as a text string (javascript does not work).
protect_from_forgery except: :new
skip_before_action :verify_authenticity_token
I have tried removing the protect_from_forgery with: :exception method in the application_controller.rb file but it does not work (just renders the javascript in the browser as a text string).
I have tried replacing "protect_from_forgery with: :exception" with "protect_from_forgery with: :null_session" and this does not work either (gives the same InvalidCrossOriginRequest error above).
I am running out of options to fix this. Again, it's only happening in production. On my local machine (via localhost), everything works fine. The code for my comments controller is below:
class CommentsController < ApplicationController
# before_action :set_comment, only: [:show, :edit, :update, :destroy]
before_action :load_topic
before_action :authenticate_user!
# protect_from_forgery except: :new
# skip_before_action :verify_authenticity_token
# GET /comments
# GET /comments.json
def index
#comments = Comment.all
end
# GET /comments/1
# GET /comments/1.json
def show
end
# GET /comments/new
def new
#comment = Comment.new
end
# GET /comments/1/edit
def edit
end
# POST /comments
# POST /comments.json
def create
#comment = #topic.comments.new(comment_params)
#comment.user_id = current_user.id
respond_to do |format|
if #comment.save
format.html { redirect_to #topic, notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: #comment }
format.js
else
format.html { redirect_to #article, alert: 'Unable to add comment' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
format.js { render 'fail_create.js.erb'}
end
end
end
# PATCH/PUT /comments/1
# PATCH/PUT /comments/1.json
def update
respond_to do |format|
if #comment.update(comment_params)
format.html { redirect_to #comment, notice: 'Comment was successfully updated.' }
format.json { render :show, status: :ok, location: #comment }
else
format.html { render :edit }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
#comment = #topic.comments.find(params[:id])
#comment.destroy
respond_to do |format|
format.html { redirect_to #topic, notice: 'Comment was successfully deleted.' }
format.json { head :no_content }
format.js
end
end
private
def load_topic
#topic = Topic.find(params[:topic_id])
end
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:topic_id, :body, :name)
end
end
Any advice on fixing this issue would be appreciated.

Has this actually happened to real users or are you only seeing this error in your logs/monitoring?
This error tends to happen when crawlers are visiting your site (which obviously doesn't happen in your development environment).
The documentation is suggesting you add these to your controller action:
skip_before_action :verify_authenticity_token, if: :json_request?
protected
def json_request?
request.format.json?
end
However, if this is not the case, I think you actually have a CORS problem. 2 possible reasons:
Is your site available via HTTP and HTTPS? These are different origins!
Do you have multiple domains running this site? Try to inspect/log the request headers and see if there is any difference in the Origins.
You can try reproducing this in development too, if you edit your hosts file and point a domain to your local server.

Related

How to access todos in another controller rails 4.2?

I'm trying to learn RoR by creating an application, however, I have come across a problem and I'm not sure if my method is flawed or if it's the correct way to do it but I'm going about it slightly wrong. I think it has something to do with the variable being an instance variable and it's not called in my other controller but I'm not sure how to get it there?
Anyway the problem is -
I have a todos controller, models, views etc. set up via the scaffolding in Rails but I want to be able to display the todos to each user in their 'dashboard' so to speak when they log in. Therefore I assume I need the todos to be in the dashboard controller too, right?
Here's my dashboard controller
class DashboardController < ApplicationController
def home
#todos = current_user.todos
end
end
Here I'm calling my todos but they aren't showing when I call them in the view.
and my todos scaffold
class TodosController < ApplicationController
before_action :set_todo, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
# GET /todos
# GET /todos.json
def index
#todos = current_user.todos
end
# GET /todos/1
# GET /todos/1.json
def show
end
# GET /todos/new
def new
#todo = Todo.new
end
# GET /todos/1/edit
def edit
end
# POST /todos
# POST /todos.json
def create
#todo = current_user.todos.new(todo_params)
respond_to do |format|
if #todo.save
format.html { redirect_to #todo, notice: 'Todo was successfully created.' }
format.json { render :show, status: :created, location: #todo }
else
format.html { render :new }
format.json { render json: #todo.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /todos/1
# PATCH/PUT /todos/1.json
def update
respond_to do |format|
if #todo.update(todo_params)
format.html { redirect_to #todo, notice: 'Todo was successfully updated.' }
format.json { render :show, status: :ok, location: #todo }
else
format.html { render :edit }
format.json { render json: #todo.errors, status: :unprocessable_entity }
end
end
end
# DELETE /todos/1
# DELETE /todos/1.json
def destroy
#todo.destroy
respond_to do |format|
format.html { redirect_to todos_url, notice: 'Todo was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_todo
#todo = Todo.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def todo_params
params.require(:todo).permit(:title, :item)
end
end
How would I go about displaying my todo items in the dashboard?
Thanks for any help
You just need to add
before_action :authenticate_user!
to DashboardController like the way you have it in TodosController .
Do you have a current user in the dashboard controller? You will need to decide how to handle that - either require sign in, or use an if else statement e.g.
def home
if current_user
#todos = current_user.todos
end
end

Sorcery gem - logged_in? always returns false

I'm trying to make a very simple web app using Rails and I'm using the Sorcery gem to authenticate users. I followed the tutorial here on their GitHub page, and I'm getting no where with it.
I have 2 issues which I believe are probably linked.
The first being, when I use this before_filter skip_before_filter :require_login, only: [:index, :new, :create], users can still access the page without logging in.
The other issue is, when a user tries to log in, they aren't redirected, and when I use the built in helper logged_in?, it always returns false. Even though there was no error message when logging in.
I've added the appropriate controllers, let me know if you need to look at anything else.
Thanks.
user_sessions_controller.rb
class UserSessionsController < ApplicationController
skip_before_filter :require_login, :except => [:destroy]
def new
#user = User.new
end
def create
if #user = login(params[:email], params[:password])
redirect_back_or_to(:users, :notice => 'Login successfull.')
else
flash.now[:alert] = 'Login failed'
render action: 'new'
end
end
def destroy
logout
redirect_to(:users, :notice => 'Logged out!')
end
end
users_controller.rb
class UsersController < ApplicationController
skip_before_filter :require_login, only: [:index, :new, :create]
# GET /users
# GET /users.json
def index
#users = User.all
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to :users, notice: 'User was 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
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
#def user_params
# params.require(:user).permit(:email, :crypted_password, :salt)
#end
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
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
protect_from_forgery
before_filter :require_login
private
def not_authenticated
redirect_to(login_path, :alert => "Please login first")
end
end
Everyone has access to Users pages due to this line skip_before_filter :require_login, only: [:index, :new, :create]. This literally means "don't check authorization". Just remove this line.
Generally you should skip require_login filter only on public pages and login pages (i.e. UserSessionsController#create etc).
And the second issue: do you have authenticates_with_sorcery! in your User model?

Rails http rest architecture

I developed a simple toy app which models a user and a micro-post using scaffolds. This is my user_controller
source "railstutorial.org"
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
#users = User.all
end
Method Show
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was 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
Method update
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :email)
end
end
Show method is used for rendering the user page with URL of the type "users/1".
However update method is to update our user's database, but after the update action is called it redirects us to the "users/1" URL.
In first case http request made is of type "GET" which routes us to "show" function/action, however in second case http request is of type "PATCH" which routes control to "update" function and this update function simply update the database, then why and how does it redirects us to "users/1". Does it call any rendering code somewhere ?
I am a beginner so please excuse me if question is a bit silly, but it would be a great help if someone could answer.
See at your code in update action after if #user.update(user_params)
You are calling redirect_to, it simply redirect you to new route which you provide it.
in this case its redirecting to show action as you are passing the object, you can provide any other route also.
read about redirect_to http://api.rubyonrails.org/classes/ActionController/Redirecting.html
#user is simply a user entry object who got an id in User Model, if you said redirect_to #user, it automatically detects the id of the user found in #user and redirects to /user/:id, rails is brave enough to understand that

My Rails controller test is not inheriting the ApplicationController methods

I have an ApplicationController with a given method in the public area
def current_user
session[:user]
end
and another controller
ObjetosController < ApplicationController
which needs to access such method, and I'm getting a horrible error while running my tests (rake test:functionals):
NameError: undefined local variable or method `current_user' for
I'm using Ruby 2.0.0 and Rails 4.0. I've been travelling Google and StackOverflow for hours and hours and haven't found anything about it.
Maybe someone can give me a hint or help me search for an answer please?
If it helps, if I put crap inside ApplicationController, and run the test, it doesn't complain!!! It's like it was loading another version of this class...
Here my ObjetosController code:
class ObjetosController < ApplicationController
before_action :set_objeto, only: [:show, :edit, :update, :destroy]
# GET /objetos
# GET /objetos.json
def index
#objetos = Objeto.all
end
# GET /objetos/1
# GET /objetos/1.json
def show
end
# GET /objetos/new
def new
#objeto = Objeto.new
end
# GET /objetos/1/edit
def edit
end
# POST /objetos
# POST /objetos.json
def create
#objeto = Objeto.new(objeto_params)
respond_to do |format|
if #objeto.save
format.html { redirect_to #objeto, notice: 'Objeto was successfully created.' }
format.json { render action: 'show', status: :created, location: #objeto }
else
format.html { render action: 'new' }
format.json { render json: #objeto.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /objetos/1
# PATCH/PUT /objetos/1.json
def update
current_user
respond_to do |format|
if #objeto.update(objeto_params)
format.html { redirect_to #objeto, notice: 'Objeto was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #objeto.errors, status: :unprocessable_entity }
end
end
end
# DELETE /objetos/1
# DELETE /objetos/1.json
def destroy
#objeto.destroy
respond_to do |format|
format.html { redirect_to objetos_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_objeto
#objeto = Objeto.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def objeto_params
params.require(:objeto).permit(:nombre, :codigo_sgej)
end
end
Solved it.
In my ApplicationController class I was instantiating some classes dynamically defined for each environment. I was also using some constants defined per environment.
As this app hasn't been released to staging or production yet, I had such values defined only in config/environments/development.rb file. I added them to config/environments/test.rb and now it works!
I lost hours with this problem, I'm really dissapointed with rails (or ruby?) for not showing any error at all...

How to show post only to logged in user in Ruby on Rails?

Okay guys, I am fairly new to rails. I have successfully created a rails app that stores login information for you. I used devise for the user management and installed cancan but no idea how to use it.
Anyways,
Right now, not matter if you are logged in or not, the site shows you all the "post" or "entrees" that have been entered by any user. I need a way to restrict this to only show post that were made by the user that is currently logged in.
I have found through research that I need do something here:
class FtpLoginsController < ApplicationController
before_action :set_ftp_login, only: [:show, :edit, :update, :destroy]
# GET /ftp_logins
# GET /ftp_logins.json
def index
#ftp_logins = FtpLogin.all
end
# GET /ftp_logins/1
# GET /ftp_logins/1.json
def show
end
# GET /ftp_logins/new
def new
#ftp_login = FtpLogin.new
end
# GET /ftp_logins/1/edit
def edit
end
# POST /ftp_logins
# POST /ftp_logins.json
def create
#ftp_login = FtpLogin.new(ftp_login_params)
respond_to do |format|
if #ftp_login.save
format.html { redirect_to #ftp_login, notice: 'Ftp login was successfully created.' }
format.json { render action: 'show', status: :created, location: #ftp_login }
else
format.html { render action: 'new' }
format.json { render json: #ftp_login.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /ftp_logins/1
# PATCH/PUT /ftp_logins/1.json
def update
respond_to do |format|
if #ftp_login.update(ftp_login_params)
format.html { redirect_to #ftp_login, notice: 'Ftp login was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #ftp_login.errors, status: :unprocessable_entity }
end
end
end
# DELETE /ftp_logins/1
# DELETE /ftp_logins/1.json
def destroy
#ftp_login.destroy
respond_to do |format|
format.html { redirect_to ftp_logins_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_ftp_login
#ftp_login = FtpLogin.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def ftp_login_params
params.require(:ftp_login).permit(:client_name, :website_name, :ftp_login, :ftp_password, :notes)
end
end
If someone could please send me in the right direction here that would be fantastic!
Thanks in advance.
for that you first have to make ensure that user is logged in before it goes to your action . so you need a before filter for that . authenticate_user! is a method given by devise . so if a user is not logged in he will redirect to the sign in page automatically
before_filter :authenticate_user!, only: [:posts, :entries]
for collecting the posts of a specific user
#posts = current_user.posts
or if it is coming for show a particular post you can do
#post = current_user.posts.where(id: params[:id])
You can use before_filter :authenticate_user!, only: [:posts, :entries] to restrict only the logged in user to view these actions.
To restrict users to view only posts created by them, you can create your own filter like
def check_user
redircet_to :back, notice: "Restricted area!" if current_user.posts.include?(#post)
end

Resources