I am getting the following error when making a post request to /locations/1/submit-to-shopify in my app:
ActionController::InvalidAuthenticityToken in LocationsController#submitshopify
You can see the post route in my routes.rb file below.
root 'home#index'
controller :sessions do
get 'login' => :new, :as => :login
post 'login' => :create, :as => :authenticate
get 'auth/shopify/callback' => :callback
get 'logout' => :destroy, :as => :logout
get 'locations/:id' => 'locations#index'
post 'locations/:id/submit-to-shopify' => 'locations#submitshopify'
end
All the other requests work fine. Here is my Locations controller:
class LocationsController < AuthenticatedController
def index
#location_id = params[:id]
#location = Location.find(#location_id)
end
def submitshopify
#location_id = params[:id]
#location = Location.find(#location_id)
#product_handle = params[:product_handle]
#product = ShopifyAPI::Product.find_by handle: #product_handle
end
def new
end
def create
end
def show
end
def edit
end
def update
end
def destroy
#location_id = params[:id]
#location = Location.find(#location_id)
#destroy_status = #location.destroy
end
end
If it is of any consequence, I am using the 'shopify_app' gem, which includes 'shopify_api'. I followed all the directions listed for both of those modules, and have successfully authenticated with Shopify in all of the other pages / controllers.
Have you used helpers to create your submission form?
or have you created it manually? If created manually, have you added the
<%= csrf_meta_tags %>
to your form?
check with your firebug if there is an authentication token at the end of the form. Even the view source should show you that.
We should be discarding that anyone is trying to spam using your form by means of a http client like curl without actually being on your site (cross site request forgery)
I am developing a web-app using Ruby on Rails (4.2.0) and I faced the implementation the login via Oauth (I followed the RailsCast tutorials #235 and #236). In particular for the authentication I implemented the following model
class Authentication < ActiveRecord::Base
# an authentication entry belongs to one user
belongs_to :user
# provider must be present
validates :provider, presence: true
# uid must be present
validates :uid, presence: true
# uniqueness of the couple user_id - provider
validates_uniqueness_of :user_id, :scope => :provider
end
and the associated create action for the authentication controller is
def create
omniauth = request.env["omniauth.auth"]
authentication =Authentication.find_by_provider_and_uid(omniauth['provider'],omniauth['uid'])
if authentication
flash[:success] = "Welcome back #{omniauth['info']['name']}!"
log_in(authentication.user)
redirect_to root_url
elsif current_user
current_user.authentications.create(provider: omniauth['provider'], uid: omniauth['uid'])
flash[:success] = "Welcome #{omniauth['info']['name']}!"
redirect_to root_url
else
user = User.new
user.authentications.build(:provider => omniauth ['provider'], :uid => omniauth['uid'])
if user.save
flash[:success] = "Signed in successfully."
redirect_to root_url
else
session[:omniauth] = omniauth.except('extra')
flash[:info] = "Just one step to go!"
redirect_to signup_url
end
end
end
While route.rb configuration file contains
match '/auth/:provider/callback' => 'authentication#create', via: [:get, :post]
Now I get stucked in writing down the controller test for two main reasons:
How can I make the post in test? With the following test unit
class AuthenticationControllerTest < ActionController::TestCase
test "post request" do
post :create
end
end
I get the following error
ActionController::UrlGenerationError: ActionController::UrlGenerationError: No route matches {:action=>"create", :controller=>"authentication"}
test/controllers/authentication_controller_test.rb:6:in `block in <class:AuthenticationControllerTest>'
test/controllers/authentication_controller_test.rb:6:in `block in <class:AuthenticationControllerTest>'
How can I create a "fake" env variable for the test?
Surfing the web I was able to find only tutorials using Capybara or Cucumber and nothing with the standard Rails tests.
Any kind of help will be really appreciated!
Andrea
I have a problem with devise_invitable 1.4.0 and strong parameters when I add additional custom parameters and I really hope somebody can guide me in the right direction. I am able to send invitations, but when an invited user accepts an invitation and enters a desired username, maiden name, password and confirmed password, the following error is shown:
Processing by Users::InvitationsController#update as HTML
Unpermitted parameters: username, name
The user is created as expected, but the 'username' and 'name' columns in the database are empty.
I have tried all the suggestions I could find for related issues, but none of the worked. I have noticed that if I change the app/controllers/users/invitations_controller.rb file in any way (eg inserting a blank space on an empty line) without restarting the webserver (Thin) the problem disappears - but the problem reappears when the webserver is restarted.
The various relevant files look like this:
routes.rb:
Rails.application.routes.draw do
root to: 'visitors#index'
#Tell rails to use the Devise controllers that were generated with this command:
# > rails generate devise:controllers users
#Using these generated controllers allows us to overwrite anything in the deault controllers.
devise_for :users, :path_names => {:sign_in => 'login', :sign_out => 'logout'}, controllers: {confirmations: "users/confirmations", passwords: "users/passwords", registrations: "users/registrations", sessions: "users/sessions", unlocks: "users/unlocks", :invitations => 'users/invitations'}
resources :users
end
config/initializers/devise.rb
Devise.setup do |config|
...
...
config.scoped_views = true
config.authentication_keys = [ :username ]
...
...
end
app/controllers/users/invitations_controller.rb:
class Users::InvitationsController < Devise::InvitationsController
private
# this is called when creating invitation
# should return an instance of resource class
def invite_resource
## skip sending emails on invite
resource_class.invite!(invite_params, current_inviter) do |u|
u.tenant = current_inviter.tenant
u.role = :user
end
end
def after_invite_path_for(resource)
users_path
end
def resource_params
params.permit(user: [:name, :email,:invitation_token, :username])[:user]
end
end
app/controllers/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
around_filter :scope_current_tenant
before_filter :configure_permitted_parameters, if: :devise_controller?
if Rails.env.development?
# https://github.com/RailsApps/rails-devise-pundit/issues/10
include Pundit
# https://github.com/elabs/pundit#ensuring-policies-are-used
# after_action :verify_authorized, except: :index
# after_action :verify_policy_scoped, only: :index
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
end
#############################################################################
private
#############################################################################
if Rails.env.development?
def user_not_authorized
flash[:alert] = "Access denied." # TODO: make sure this isn't hard coded English.
redirect_to (request.referrer || root_path) # Send them back to them page they came from, or to the root page.
end
end
def current_tenant
#current_tenant ||= current_user.tenant unless current_user.nil?
end
helper_method :current_tenant
def scope_current_tenant(&block)
if current_tenant.nil?
scope_visitor_schema
yield
else
current_tenant.scope_schema("public", &block)
end
end
def scope_visitor_schema()
original_search_path = ActiveRecord::Base.connection.schema_search_path
ActiveRecord::Base.connection.schema_search_path = 'public'
ensure
ActiveRecord::Base.connection.schema_search_path = original_search_path
end
#############################################################################
protected
#############################################################################
def configure_permitted_parameters
# Only add some parameters
devise_parameter_sanitizer.for(:account_update).concat [:name, :email]
# Override accepted parameters
devise_parameter_sanitizer.for(:accept_invitation) do |u|
u.permit(:name, :username, :password, :password_confirmation,
:invitation_token)
end
end
end
app/models/user.rb:
class User < ActiveRecord::Base
enum role: [:user, :admin]
after_initialize :create_tenant, :if => :new_record?
belongs_to :tenant
# has_many :invitations, :class_name => self.to_s, :as => :invited_by
scope :unconfirmed, -> { where(confirmed_at: nil) }
scope :confirmed, -> { where.not(confirmed_at: nil) }
# validate :username, presence: true, uniqueness: true, format: { with: /[a-zA-Z0-9]{4,20}/ }
def displayed_username
username.nil? ? "N/A" : username
end
def displayed_name
name.nil? ? "N/A" : name.titleize
end
def create_tenant
#The create_tenant method will also be called when looking up a user,
#so the following ensures a tenant is only created if it does not already
#exist - and the user has not been invited and assigned to an existing tenant:
if self.tenant.nil?
#Set role to 'admin' if a tenant is about to be created:
self.role = :admin #if self.tenant.nil?
self.tenant = Tenant.new
end
end
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :invitable, :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
end
I finally found a fix, which was to place the parameter sanitizer directly in users/invitations_controller.rb instead of the application_controller.rb.
class Users::InvitationsController < Devise::InvitationsController
before_filter :configure_permitted_parameters, if: :devise_controller?
private
def configure_permitted_parameters
devise_parameter_sanitizer.for(:accept_invitation) do |u|
u.permit(:username, :name, :email, :password, :password_confirmation, :invitation_token)
end
end
end
So this is probably going to be a very dumb question but i've set up Oauth with twitter as the provider in a similar way to Ryan Bates's 'Simple Omniauth Railscast - my question is now that that is set up and working should i be setting strong parameters in my sessions controller or is this not necessary?
SessionsController.rb
class SessionsController < ApplicationController
def create
#user = User.find_by_uid(auth_hash[:uid]) || User.create_user(auth_hash)
session[:uid] = #user.id
if #user
redirect_to root_path
else
redirect_to root_path, flash: {signinerror: "Oops, something went wrong with your sign in. Please try again."}
end
end
def auth_hash
request.env['omniauth.auth']
end
def destroy
session[:uid] = nil
redirect_to root_path
end
end
User.rb
class User < ActiveRecord::Base
has_many :opinions
def self.create_user(auth_hash)
create do |user|
user.provider = auth_hash[:provider]
user.name = auth_hash[:info][:name]
user.uid = auth_hash[:uid]
user.username = auth_hash[:info][:nickname]
user.email = auth_hash[:info][:email]
user.image = auth_hash[:info][:image]
end
end
end
Thanks
Since you don't use mass assignment on object creation, strong parameters will not give you any additional security.
With this plugin Action Controller parameters are forbidden to be used in Active Model mass assignments until they have been whitelisted.
https://github.com/rails/strong_parameters
I am using stripe checkout for my payment solution within and e-commerce app. I want to create an order after a successful charge.
At the moment once payment is successful I just change a "success" boolean attribute on the current cart before destroying the cart. I will like to create an order instead so the cart object does not have to deal with this extra responsibility.
My problem is that I do not know where to tell my controller to create an order and how to pass data from the current cart to the order object.
Here is the charges controller setup
class ChargesController < ApplicationController
def new
#user = current_user
#cart = current_cart
#amount = #cart.total_price
end
def create
#amount = #cart.total_price
customer = Stripe::Customer.create(
:email => #user.email,
:card => params[:stripeToken]
)
charge = Stripe::Charge.create(
:customer => #user.id,
:amount => #amount,
:description => 'Rails Stripe customer',
:currency => 'usd'
)
# this changes the status of the current cart to success
#cart.update_status(current_cart)
session[:cart_id] = nil
redirect_to current_user, notice: 'You placed an order!'
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to charges_path
end
end