rails 3 redirect_to pass params to a named route - ruby

I am not finding much info on how to do this even though there are lots of suggestions on how to pass params to a redirect using hashs like this redirect_to
:action => 'something', :controller => 'something'
in my app I have the following in the routes file
match 'profile' => 'User#show'
my show action loos like this
def show
#user = User.find(params[:user])
#title = #user.first_name
end
the redirect happens in the same user controller like this
def register
#title = "Registration"
#user = User.new(params[:user])
if #user.save
redirect_to '/profile'
end
end
The question is in the register action when I redirect_to how do I pass along the params so I can grab that user from the database or better yet ... I already have a user variable so how do I pass along the user object to the show action?
-matthew

If you're doing a redirect, Rails will actually send a 302 Moved response with a URL to the browser and the browser will send another request to that URL. So you cannot "pass the user object" as in Ruby, you can only pass some url encoded parameters.
In this case you would probably want to change your routing definition to:
match 'profile/:id' => 'User#show'
and then redirect like this:
redirect_to "/profile/#{#user.id}"

First off, I'd name your route, to make using it easier:
match '/profile/:id' => 'users#show', :as => :profile
You would then redirect to it, like so:
redirect_to profile_path(#user) # might have to use profile_path(:id => #user.id)
Then to pull the user from the database:
def show
#user = User.find(params[:id]) # :id comes from the route '/profile/:id'
...
end
As an aside, if you use something like Devise for authentication, it provides you with a current_user method, and therefore you wont need to pass around the user's id:
match '/profile' => 'users#show', :as => :profile
redirect_to profile_path
def show
#user = current_user
end

Related

Trying to prevent duplicate username creation in Sinatra app

Hi I am trying to prevent duplicate user name creation, and my application keeps trying to redirect me to a hypothetical account page and keeps throwing username undefined error in my erb file, and I am actually trying to redirect back to signup page if the user name already exist.
Here is my model for User class:
class User <ActiveRecord::Base
include Slugifiable::InstanceMethods
extend Slugifiable::ClassMethods
validates_uniqueness_of :username, case_sensitive: false <---This should validate if username exist
has_many :players
has_secure_password
end
Here is my user controller post method where it should either create or redirect back to signup page and give a flash message that the user name exist already
post '/signup' do
if params[:username] == "" || params[:email] == "" || params[:password] == "" || params[:name] == ""
flash[:notice] = "<h3 class ='alert'>Please fill-in info!</h3>"
redirect to '/signup'
else
if #user
flash[:notice] = "<h3>Username already exist, try anoter one.</h3>"
redirect to '/signup'
else
#user = User.create(:username => params[:username], :email => params[:email], :password =>
params[:password], :name => params[:name])
session[:user_id] = #user.id
redirect to '/account'
end
end
end
When I try to create a duplicate username for testing purposes....it keeps redirecting me to an account page but throws an error that username is undefined from erb file. It works fine when creating a completely new username though. What am I doing wrong?
"throws an error ... from erb" sounds like there's an issue in an ERB file somewhere?
User.create probably silently fails when the uniqueness check triggers, i.e. it sounds like it sets #user.username to nil, or #user itself is nil.
You also never defined what it should do when the validation check fails.
You can:
use User.create! to raise an exception.
check #user.valid? and #user.errors for any errors, and report them to the user

Shopify Webhook not sending to controller

Thru the Shopify API I can create webhooks great. I've created ones that point to RequestBin just fine, the data that is sent to RequestBin is perfect. But when I turn it towards my own controllers nothing happens. I have a binding.pry in my controller to catch anything that comes in, and nothing ever comes in. Not sure why??
Here is me creating the hook with the ShopifyAPI gem:
webhook = ShopifyAPI::Webhook.create(:topic => "carts/update",
:format => "json",:address => "https://dyno-shipping-trimakas.c9users.io
/webhook/cart_callback/")
And then here it is verified when I list the webhooks:
{"id"=>226014599,
"address"=>
"https://dyno-shipping-trimakas.c9users.io/webhook/cart_callback/",
"topic"=>"carts/create",
"created_at"=>"2016-02-24T17:20:02-05:00",
"updated_at"=>"2016-02-24T17:20:02-05:00",
"format"=>"json",
"fields"=>[],
"metafield_namespaces"=>[]}
This is my controller:
class WebHookController < ApplicationController
skip_before_action :verify_authenticity_token, only: [:cart_callback]
def cart_callback
binding.pry
x = params
pp x
end
end
Then finally this is my route:
scope '/webhook', :controller => :webhook do
post :cart_callback
end
Not sure where I went astray??

'Refused to display in frame.' Facebook Oauth dialog

I'm having some trouble authenticating users for my app. During the authentication process I get the following error:
Refused to display 'https://www.facebook.com/dialog/oauth?response_type=code&client_id=xxxxxxxx…%2Fliketodownload.xx-xxxx.com%2Fauth%2Ffacebook%2Fcallback&scope=email' in a frame because it set 'X-Frame-Options' to 'DENY'.
I think it's to do with the authentication trying to redirected to an invalid target and that's why it's getting blocked. But with Ruby and Sinatra I am unsure of how to overcome this.
Many thanks.
UPDATE
I'm not redirecting to views, of which the auth and add to page dialogs are trigged into new targets via html. Now I'm trying to figure out the logic of which to auth and redirect users appropriately.
Code below:
post '/' do
if current_user
signed_request = FBGraph::Canvas.parse_signed_request(APP_SECRET, params[:signed_request])
if signed_request["page"] != nil
is_admin = signed_request["page"]["admin"]
is_liked = signed_request["page"]["liked"]
if is_admin #if admin, see if existing user is in db, if not create, then send to admin page
puts "user is a page admin" #logging for dev
redirect '/index'
elsif is_liked #if liked send to download end point
puts "user has liked page" #logging for dev purposes
redirect '/main/#/liked'
elsif !is_liked #otherwise make them like the page
puts "user has not liked" #logging for dev purposes
redirect '/main/#/notliked'
end
else
redirect '/addtopage/#/addtopageview'
end
elsif $auth1 && !current_user
puts "post / add to page view reached"
User.first_or_create({:uid => $auth1["uid"]}, {
:uid => $auth1["uid"],
:nickname => $auth1["info"]["nickname"],
:name => $auth1["info"]["name"],
:email_address => $auth1["info"]["email"],
:created_at => Time.now})
redirect '/addtopage/#/addtopageview'
else
# we just redirect to /auth/facebook here which will parse the #signed_request FB sends us, asking for auth if the user has not already granted access, or simply moving straight to the callback where they have already granted access.
puts "post / auth me reached"
redirect '/addtopage/#/authme'
end
end
get '/auth/:provider/callback' do
content_type 'application/json'
response.set_cookie 'test', {:value => "facebook_callback", :path => "/"}
JSON.generate(request.env)
auth = request.env["omniauth.auth"]
$auth1 = auth
#need escape here to allow user to initially authorise app without the full #signed_request?
session['fb_auth'] = auth
session['fb_token'] = cookies[:fb_token] = auth['credentials']['token']
session['fb_error'] = nil
if params[:signed_request] != nil #if the signed request isn't empty
signed_request = FBGraph::Canvas.parse_signed_request(APP_SECRET, params[:signed_request])
if signed_request["page"] != nil #if the signed request contains page data
$page_id = signed_request["page"]["id"]
is_admin = signed_request["page"]["admin"]
is_liked = signed_request["page"]["liked"]
if is_admin #if admin, see if existing user is in db, if not create, then send to admin page
puts "user is a page admin" #logging for dev
User.first_or_create({:uid => auth["uid"]}, {
:uid => auth["uid"],
:nickname => auth["info"]["nickname"],
:name => auth["info"]["name"],
:email_address => auth["info"]["email"],
:created_at => Time.now})
#insert page_id into database?
redirect '/index'
elsif is_liked #if liked send to download end point
puts "user has liked page" #logging for dev purposes
redirect '/main/#/liked'
elsif !is_liked #otherwise make them like the page
puts "user has not liked" #logging for dev purposes
redirect '/main/#/notliked'
end
else #user authed app but needs to add to page
puts "add to page view"
redirect '/addtopage/#/addtopageview'
end
else
#needs to redirect to a page telling them that they must be on facebook or that they must authorise the application
redirect '/index'
end
end
helpers do
def current_user
#current_user ||= User.get(session[:user_id]) if session[:user_id]
end
end
Facebook domains can not be iframed except for the socials plugins, Why?
for security reasons, for example let's say you're logged into Your Facebook account
and I have http://example.com/xss.html which has an iframe of http://facebook.com in this way I can steal or hi-jack sensitive information from your account like fb_dtsg token, same thing for oAuth Dialogs I can set my iframe source to to it and steal Your access_token :)
I hope it's clear enough why Facebook uses
header('X-Frame-Options: DENY');

Why does respond_with JSON not work?

I'm having a problem when trying to use the return to in a rails controller. This is not working:
class UsersController < ApplicationController
respond_to :json
def create
#user = User.create params[:user_info]
respond_with #user
end
end
This works:
class UsersController < ApplicationController
respond_to :json
def create
#user = User.create params[:user_info]
respond_with #user do |format|
format.json { render json: #user.to_json }
end
end
end
Why? This is the error I have in the server's log when using the one that doesn't work:
NoMethodError (undefined method `user_url' for #<UsersController:0x007fd44d83ea90>):
app/controllers/users_controller.rb:7:in `create'
My route is:
resources :users, :only => [:create]
responds_with tries to redirect to user_url, so it looks for a show method in your user controller, which you don't have, since your route is limited to the create method only. Since the create method redirects to the show method by default this doesn't work. But in your second version you are actually rendering something, so no redirection happens.
You can give a :location option to respond_with if that's what you want, like so:
respond_with(#user, :location => home_url)
or use the render version as you do in your second version.

Couldn't find <object> without an ID rails 3.0.1

Unfortunately, this is my second post in as many days. So the application worked fine with mysql and rails 3.0.3 but I found out that I needed to use MSSQL so I had to downgrade rails to 3.0.1.
In a nutshell, I copied the show.html.erb as show2.html.erb and created a new method which is a copy of the show method. Then I created a route match.
my controller
class fathersController < ApplicationController
def show
#father= Father.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #father}
end
end
def show2
#father= Father.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #father}
end
end
end
routes.rb
resources :fathers do
match '/show2' => 'fathers#show2'
resources :kids
end
when I call
http://127.0.0.1:3000/father/1
I get the show view but when I call
http://127.0.0.1:3000/father/1/show2
I get the following error
Couldn't find father without an ID
The request Parameters come back as
{"father_id"=>"1"}
so I know that the problem is that the app is passing the id as father_id but how do I fix it? Any help would be appreciated.
There are two problems.
You're trying to use a non-resourceful route on a route that actually should be resourceful.
It looks like you're trying to send /show2 to a controller named hospitals, when your action is actually specified on the fathers controller.
This should do the trick:
resources :fathers do
get :show2, :on => :member
resources :kids
end
You can also write the above as:
resources :fathers do
member do
get :show2
end
resources :kids
end

Resources