I've got a very simple app where the flow looks like this:
User reads some copy, decides they want to purchase the product and fill out the form, see confirmation page.
Something is wrong in my controller but I can't quite pinpoint it where I'm getting the error Couldn't find Customer without an ID.
class CustomersController < ApplicationController
# before_filter :load_customer, :only => :show
def new
#customer = Customer.new
end
def create
#customer = Customer.new(params[:customer])
if #customer.save
session[:customer_id] = #customer.id
purchase
else
flash[:error] = "Please enter a valid email address"
redirect_to :signup
end
end
def signup
#customer = Customer.new
end
def purchase
Stripe.api_key = STRIPE['secret']
charge = Stripe::Charge.create(
:amount => 2000,
:currency => "usd",
:card => params[:stripe_token],
:description => "My Product Name"
)
redirect_to receipt_path
end
def receipt
#customer = Customer.find(session[:customer_id])
#name = #customer.name
#email = #customer.email
#product = #customer.product
end
# private
#
# def load_customer
# #customer = Customer.find(session[:customer_id])
# redirect_to request.path.gsub(params[:id], session[:customer_id].to_s) if params[:id] != session[:customer_id].to_s
# end
end
I'm not sure where things are screwing up and after much Googling, I'm turning to you guys. Help would be huge.
EDIT:
Consulting with Rails console shows that my application isn't making new customer records for some reason. Charging is working, however. Customers not being created must be a precursor to this.
EDIT 2: Development.log
Started GET "/assets/bootstrap.js?body=1" for 127.0.0.1 at 2012-08-28 15:58:11 -0700
Served asset /bootstrap.js - 304 Not Modified (0ms)
[2012-08-28 15:58:11] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
Started POST "/checkout" for 127.0.0.1 at 2012-08-28 15:58:12 -0700
Processing by CustomersController#purchase as HTML
Parameters: {"utf8"=>"โ", "authenticity_token"=>"k2aW/CAkNfwDSMHHvzbuOwm+Xua0qb2LJ4LtrtRvyvk=", "customer"=>{"name"=>"Your name", "email"=>"yourname#example.com"}, "stripe_token"=>"tok_0GUvwKPwo6jfEu"}
Redirected to http://localhost:3000/receipt
Completed 302 Found in 1064ms (ActiveRecord: 0.0ms)
Started GET "/receipt" for 127.0.0.1 at 2012-08-28 15:58:14 -0700
Processing by CustomersController#receipt as HTML
Completed 500 Internal Server Error in 0ms
ActiveRecord::RecordNotFound (Couldn't find Customer without an ID):
app/controllers/customers_controller.rb:38:in `receipt'
Rendered /Users/zack/.rvm/gems/ruby-1.9.3-p194#beat-the-herd/gems/actionpack-3.2.2/lib/action_dispatch/middleware/templates/rescues/_trace.erb (3.9ms)
Rendered /Users/zack/.rvm/gems/ruby-1.9.3-p194#beat-the-herd/gems/actionpack-3.2.2/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (5.6ms)
Rendered /Users/zack/.rvm/gems/ruby-1.9.3-p194#beat-the-herd/gems/actionpack-3.2.2/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (23.7ms)
If the user routes directly to receipt action then session[:customer_id] may be nil. That's why you get the error. This is not happened if a create (possibly) POST request is issued. In this case, the session variable has been populated before the redirection to the receipt action.
This line :
#customer = Customer.find(session[:customer_id])
throws an error because session[:customer_id] is nil
You might want to use find_by_id that won't throw an Exception but will return an nil record.
Then you'll have to deal with the case of #customer being nil.
Add this in UserController
def show <br>
#user = User.find(session[:user_id])<br>
#profile = #user.profile<br>
end
Rather than putting "user_id" put session[:user_id]
It worked for me
Related
I have this piece of code which is triggered when a new order is created in my Shopify store:
class CustomwebhooksController < ShopifyApp::WebhooksController
#the line below is to avoid the CSR error
protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }
include ShopifyApp::WebhookVerification
# This method is triggered when the user completes the checkout process
# Gets the order number and see the message "Your order is confirmed"
# I should use this as the trigger to update the other SKU for the DT solution:
def orders_create
request.body.rewind
data = JSON.parse(request.body.read)
#redirect_to controller: "home", action: "update_stock", status: :found
#MyHomeController = HomeController.new
#MyHomeController.update_stock
#do not remove line below
head :ok
end
end
This is the code in my home controller:
class HomeController < ShopifyApp::AuthenticatedController
def update_stock
#products = ShopifyAPI::Product.find(:all, :params => {:title => 'DT382'})
#products.each do |product|
puts(product.id)
end
end
end
Somehow the call to #MyHomeController.update_stock generates a 302 as shown below:
Rendered inline template (0.4ms)
Completed 302 Found in 689ms (Views: 0.9ms | ActiveRecord: 0.0ms)
Am I missing anything?
I would like to challenge your design for a minute.
Firstly, if you're going to redirect to a different controller/action, why aren't you using redirect_to update_stock_path where the path is specified in your routes file?
Secondly, why redirect at all? You're receiving a webhook with some payload and then you need to hit the Shopify API to get product data. To me, this is far more suitable as a background job. Furthermore, designing this as receive webhook -> schedule background job -> do work in the job will be more scalable than what you're doing now.
I managed to figure out the solution after carefully reading the Shopify API documentation.
class HomeController < ShopifyApp::AuthenticatedController
def update_stock
shop_url = "https://#{ENV['API_KEY']}:#{ENV['API_SECRET']}#myshopifyshop.myshopify.com/admin"
ShopifyAPI::Base.site = shop_url
#products = ShopifyAPI::Product.find(:all, :params => {:title => 'DT382'})
#products.each do |product|
puts(product.id)
end
ShopifyAPI::Base.clear_session
end
end
Im working on my Rails Backend in Ruby and i want to post Data to this server. But if i do a Post-request with PAW i get redirected. Im a newbie to Http Requests. Could someone explain me the functionality and how to use http post requests?
i want to post information on my server's datanase (sqlite3).
Here's a screenshot which should explain everything:
how does this work? please explain :)
thanks.
greetings John
and here's the code:
OwnersController:
#app/controllers/owners_controller.rb
class OwnersController < SessionsController
respond_to :html
before_action :owner_find, only: [:show, :edit, :update, :destroy]
def index
#owners = Owner.all
end
def show
end
def update
#owner = Owner.find(params[:id])
if #owner.update(owner_params)
redirect_to #owner
else
render 'edit'
end
end
def new
#owner = Owner.new
end
def destroy
#owner.destroy
redirect_to owners_path
end
def edit
end
def create
#owner = Owner.new owner_params
if #owner.save!
flash[:notice] = 'You signed up successfully'
flash[:color]= 'valid'
redirect_to owners_path
else
flash[:notice] = 'Form is invalid'
flash[:color]= 'invalid'
render 'new'
end
end
private
def owner_find
#owner = Owner.find(params[:id])
end
def owner_params
params.require(:owner).permit(:name, :password, :password_confirmation, :token)
end
end
SessionController:
class SessionsController < ApplicationController
before_filter :authenticate_user, :except => [:login, :login_attempt]
def login
#goes to Login Form
end
def logout
session[:owner_id] = nil
redirect_to :action => 'login'
end
def login_attempt
authorized_user = Owner.authenticate_by_name(params[:login_name],params[:login_password])
if authorized_user
session[:owner_id] = authorized_user.id
flash[:notice] = "Wow Welcome again, you logged in as #{authorized_user.name}"
redirect_to welcome_index_path
else
flash[:notice] = 'Invalid Username or Password'
flash[:color]= 'invalid'
render 'login'
end
end
end
Console Logs:
from web-request (http://192.168.2.144:3000/owners?name=hans&password=hans321&password_confirmation=hans321)
Started GET "/owners?name=hans&password=[FILTERED]&password_confirmation=[FILTERED]" for 192.168.2.144 at 2015-10-01 12:12:18 +0200
Cannot render console from 192.168.2.144! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by OwnersController#index as HTML
Parameters: {"name"=>"hans", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}
Owner Load (0.1ms) SELECT "owners".* FROM "owners" WHERE "owners"."id" = ? LIMIT 1 [["id", 2]]
Owner Load (0.1ms) SELECT "owners".* FROM "owners"
Rendered owners/index.html.erb within layouts/application (1.8ms)
Completed 200 OK in 60ms (Views: 58.9ms | ActiveRecord: 0.2ms)
It's telling 200 ok but nothing happens in the DB.
from Paw-Request (so i can use post. btw. how do i use post in browser request?
Started POST
"/owners?name=hans&password=[FILTERED]&password_confirmation=[FILTERED]"
for 192.168.2.144 at 2015-10-01 12:12:45 +0200 Cannot render console
from 192.168.2.144! Allowed networks: 127.0.0.1, ::1,
127.0.0.0/127.255.255.255 Processing by OwnersController#create as HTML Parameters: {"name"=>"hans", "password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]"} Can't verify CSRF token
authenticity Redirected to http://192.168.2.144:3000/ Filter chain
halted as :authenticate_user rendered or redirected Completed 302
Found in 1ms (ActiveRecord: 0.0ms)
It seems that the CRSF authentication failed..
Edit:
at first:
to Rich Peck! This helped me so much. Thank you!! I really appreciate your effort.
Im near to the solution.. My problem is: i cant put the correct params in the url. The token-auth is disabled for testing. so it wont matter.
the params should be like:
Parameters: {"utf8"=>"โ", "authenticity_token"=>"q9JvFhoSUgfydFTvh18JHbIIdKNDjnOS9m/trVBu9EHPP04xGsO69zPh1BFZBI1Ev1YcnOTiPmaAiPWOSkm5Xg==", "owner"=>{"name"=>"Hubert", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Create Owner"}
and not as in my request:
Parameters: {"name"=>"Hubert", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "owner"=>{}}
HTTP Status Codes
Firstly, a 30x response means "Resource Moved".
301 responses are used by many SEO people to denote permanent relocation of resources. 302 not so common, but still means a similar thing.
Every time you send & receive HTTP requests, you're going to receive a status code. The typical is the 200 response -- status success!
What you're seeing is the redirect_to command in action -
if #owner.save!
flash[:notice] = ...
redirect_to owners_path
I've never used PAW before, but I assume it's just giving you the pure response of the server, which would in this case be a 30x "Resource Moved" code.
I would expect a typical browser request to load the redirected route and display its yield on the screen.
Server
As a way to test this, you should attempt the same transaction in your browser:
lvh.me:3000/orders
(lvh.me is a domain routed to your own localhost which helps with subdomains in Rails)
This will give you the ability to test and see what happens with the responses. You *should * find that your data has been saved to the database (albeit SQLite3 in your case).
Syntax
Finally, you need to ensure you're using the correct syntax in your code.
Specifically:
#app/controllers/owners_controller.rb
class OwnersController < ApplicationController
...
def create
#owner = Owner.new owner_params
end
private
def owner_params
params.require(:owner).permit(:name, :password, :password_confirmation)
end
end
You'll also want to look at bcrypt-ruby for protecting your passwords.
Testing
I tend to just test my Rails apps with standard browser functionality.
This means you can run the Rails Server ($ rails s in your console), which you'll then be able to then access through your browser.
You're trying to use this PAW thing, which is okay, but doesn't give you much flexibility in regard to the user-interactivity of the app (for example, submitting real forms etc)...
In your case, I'd do the following:
#app/views/orders/new.html.erb
<%= form_for #order do |f| %>
<%= f.text_field :name %>
<%= f.password_field :password %>
<%= f.password_field :password_confirmation %>
<%= f.submit %>
<% end %>
You'd then access lvh.me:3000/orders/new and submit the form. This will show you how it responds!
HTTP
Okay here's the deal with HTTP requests...
Whenever you send a piece of transactional data to your web application, you do it through an HTTP request. HTTP requests are just a way to send data through the "Internet".
With Rails based apps, this means that every time you "do" something in the app, you're really sending an HTTP request to your web server. Rails interprets this request and sends a response. This response is what your question is about.
You're asking about receiving 302 responses - this is the web server's way of saying you've been redirected. It's pretty basic stuff to be honest; your browser handles most of it.
A great tutorial can be found here:
Alright then your error is as follows:
Can't verify CSRF token authenticity
I can elaborate more on this later, but for now, you might want to look up this solution: WARNING: Can't verify CSRF token authenticity in case of API development
I'm running into a perplexing issue that I can only resolve partway, and hopefully, someone more experienced can tell me whether I can achieve what I wish, or if I'm barking up the wrong tree.
I have a Rails 4 application which uses Devise and CanCan. I'd like to make a small subset of application functionality available to guest users (not logged in). I can achieve this by specifying a get route to a controller method and using link_to to reach that method. I cannot, however, figure out how to get the value of a select box to pass along as parameters on that page without making that view a form using form_tag (there is no model associated with this view).
I can pass hardcoded params along like so:
<%= link_to "Month", activities_search_month_path(:resource_id => 4) %>
but I'd rather have something like:
<%= link_to "Month", activities_search_month_path(:foo => :resource_id) %>
where the second symbol refers to the value of a select_tag. This second example delivers a literal value of "resource_id" when I dump the :foo key unless I convert my view to a form.
If I turn the view into a form by enclosing all the erb in a form_tag, I get a 401 Forbidden error, after which the Devise sign in form is rendered. My guess is that any time you want to process a form, Rails (or Devise) demands authentication on some level. The behavior is the same when I use button_to rather than link_to, since button_to wraps itself in a form under the covers.
How can I set that resource_id argument in my link_to, or will I be forced to create a guest user access level and silently log in guest users? It's important for the UX that users can access this functionality with the least amount of effort possible.
Thanks in advance.
Addendum: quick_search method from controller
def quick_search
puts "quick search 0"
if(params[:time_period] == 'today')
#resource = Resource.find(params[:resource_id])
#site = Site.find(params[:site_id])
#time_period_string = "Activities for #{localize_date(Date.today)} at #{#resource.name}, #{#site.name}"
puts "quick search 1"
if user_signed_in?
puts "quick search 2a"
#activities = Activity.where("system_id = ? and start_date = ? and activity_status_id = ? and resource_id = ?", current_system_id, #today, 2, params[:resource_id])
else
puts "quick search 2b"
if(Setting["#{current_subdomain_not_signed_in}.quick_search_guest_access"] == 'true')
puts "quick search 3a"
current_system_id = current_system_id_not_signed_in
#activities = Activity.where("system_id = ? and start_date = ? and activity_status_id = ? and resource_id = ?", current_system_id, #today, 2, params[:resource_id])
else
puts "quick search 3b"
redirect_to '/users/sign_in'
end
end
end
Note: the quick_search method is never entered. CanCan (or maybe Devise) steps in immediately and redirects to sign in:
Console output:
Started GET "/activities/quick_search" for 127.0.0.1 at 2015-04-12 18:01:58 -0700
Processing by ActivitiesController#quick_search as HTML
(0.2ms) SELECT DISTINCT "systems"."subdomain" FROM "systems"
Completed 401 Unauthorized in 1ms
Started GET "/users/sign_in" for 127.0.0.1 at 2015-04-12 18:01:58 -0700
Processing by Devise::SessionsController#new as HTML
(0.2ms) SELECT DISTINCT "systems"."subdomain" FROM "systems"
Rendered layouts/_header.html.erb (0.8ms)
Rendered devise/shared/_links.html.erb (4.1ms)
Rendered devise/sessions/new.html.erb within layouts/application (14.7ms)
Rendered layouts/_footer.html.erb (0.0ms)
Completed 200 OK in 285ms (Views: 282.3ms | ActiveRecord: 0.2ms)
Ability.rb
can :quick_search, Activity
can :search_day, Activity
can :search_week, Activity
can :search_month, Activity
The odd thing is that link_to quick_search fails with a 401, but link_to the other three methods works fine -- I just can't get parameters to them dynamically.
If you are using CanCan(Can?) you can define a special ability for guests.
How does your Ability-model look?
Which controller are handling the action that you want to view?
How do you authenticate with CanCan in this controller?
https://github.com/CanCanCommunity/cancancan/wiki/CanCan-2.0
Under the "Defining Abilities" you can see a non-user example.
Fixing CanCan is probably the best option, if you do not want to:
For the part with the link and select box it would be easiest to handle as a form and then handle the redirect in the controller, it could also be done with a remote ajax form.
http://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html
This should work:
<% form_tag Activity, activity_quick_search_path, remote: true do %>
<%= select_tag :resource_id...%>
<%= submit_tag %>
<%end%>
Edit after comments:
The culprit here is(was) an:
before_action :authenticate_user!
Causing Devise to redirect to sign in page.
However, if you have CanCan you shouldn't need the authenticate_user.
Short example:
With only Devise I would do:
class NewsController < ApplicationController
before_action :authenticate_user!
before_action :set_news, except: [ :index, :new ]
def index
#news = News.all
end
def show
end
def new
#news = News.new
end
def edit
end
def create
#news = News.new(news_params)
flash[:notice] = 'News created' if #news.save!
redirect_to #news
end
def update
#news.update! news_params
redirect_to #news
end
def destroy
#news.destroy!
redirect_to News
end
private
def news_params
params.require(:news).permit(some_attributes)
end
def set_news
#news = News.find(params[:id])
end
end
How it looks with CanCanCan:
class NewsController < ApplicationController
load_and_authorize_resource
def index
end
def show
end
def new
end
def edit
end
def create
flash[:notice] = 'News created' if #news.save!
redirect_to #news
end
def update
#news.update! news_params
redirect_to #news
end
def destroy
#news.destroy!
redirect_to News
end
private
def news_params
params.require(:news).permit(some_attributes)
end
end
Which I find super neat ๐
Hope that this can help as well.
I'm working through Ruby on Rails 4 Essential Training from Lynda.com and I'm running in this error:
ActionController::ParameterMissing in SubjectsController#create
I basically have a form with 3 inputs, :name, :position, and :visible. I can enter the the information just fine but then I get the error when I hit the submit button. Here is the output from the server:
`Started POST "/subjects/create" for 127.0.0.1 at 2014-11-11 18:02:12 -0500
Processing by SubjectsController#create as HTML
Parameters: {"utf8"=>"โ", "authenticity_token"=>"f6+AdWN3jWO6mL9jrPDgVGoAm/NTBF1GPxGasTaqMh0=", "subject"=>{"name"
=>"Default", "position"=>"5", "visible"=>"false"}, "commit"=>"Create Subject"}
(0.0ms) BEGIN
SQL (1.0ms) INSERT INTO `subjects` (`created_at`, `name`, `position`, `updated_at`) VALUES ('2014-11-11 23:02:12'
, 'Default', 5, '2014-11-11 23:02:12')
(4931.3ms) COMMIT
Redirected to http://localhost:3000/subjects/create?actions=index
Completed 302 Found in 4941ms (ActiveRecord: 4932.3ms)
Started GET "/subjects/create?actions=index" for 127.0.0.1 at 2014-11-11 18:02:17 -0500
Processing by SubjectsController#create as HTML
Parameters: {"actions"=>"index"}
Completed 400 Bad Request in 1ms
ActionController::ParameterMissing (param is missing or the value is empty: subject):
app/controllers/subjects_controller.rb:40:in `subject_params'
app/controllers/subjects_controller.rb:18:in `create'
SubjectsController
class SubjectsController < ApplicationController
layout false
def index
#subjects = Subject.sorted
end
def show
#subject = Subject.find(params[:id])
end
def new
#subject = Subject.new({:name => "Default"})
end
def create
#subject = Subject.new(subject_params)
if #subject.save
redirect_to(:actions => 'index')
# raise params.inspect
else
render('new')
end
end
def edit
end
def delete
end
private
def subject_params
# same as using "params[:subject]", except that it:
# - raises an error if :subject is not present
# - allows listed attributes to be mass-assigned
params.require(:subject).permit(:name, :position, :visible)
end
end
Looking at the server output it doesn't look like I'm passing the :visible attribute to the database even though the data shows up on the index page even after the error.
I donโt think :visible is the problem, looking at your logs, you are getting this error:
ActionController::ParameterMissing (param is missing or the value is empty: subject):
app/controllers/subjects_controller.rb:40:in `subject_params'
app/controllers/subjects_controller.rb:18:in `create'
This is because of this line:
Started GET "/subjects/create?actions=index" for 127.0.0.1 at 2014-11-11 18:02:17 -0500
Processing by SubjectsController#create as HTML
Parameters: {"actions"=>"index"}
Looks like you are redirecting to GET /subjects/create and passing in parameters actions=index, likely caused by this line in your controller:
redirect_to(:actions => 'index')
I think what you meant here was really :action (singular):
redirect_to(:action => 'index')
Regarding the issue with :visible not being saved, I canโt say much without knowing anything about the model, has visible been declared in the database schema?
When using strong_params and getting an ActiveModel::ForbiddenAttributesError exception, how do I find out which attribute is forbidden? I've just switched from attr_accessible and the debug message was normally pretty good there but not when switching to strong params.
I receive this error:
ActiveModel::ForbiddenAttributesError in SnippetsController#create
This is a nested model.
def snip_params
params.require(:snippet).permit(:content, :approved, :user_id, :book_id)
end
In the parent I've used
has_nested_attributes :snippets
The create
def create
#snippet = #book.snippets.create(snip_params)
#snippet.user = current_user
if #snippet.save
redirect_to #book
flash[:success] = "Snippet submitted and awaiting approval."
else
flash[:base] = "Someone else has submitted a snippet, please try again later"
redirect_to #book
end
end
Params Contents:
{"utf8"=>"โ",
"authenticity_token"=>"bTRSwFRIhN3l3DkkWPtLzpoQHYD+CezmJQLw8Oz5+3g=",
"snippet"=>{"content"=>"<p>AAAAAAAAAAAAA</p>\r\n"},
"commit"=>"Create Snippet",
"book_id"=>"1"}
All attributes are forbidden initially. This exception is only raised when you don't permit any attributes. If you permit some and not others, then the log output tells you which parameters were not permitted.
params = ActionController::Parameters.new(name: 'Bob', age: 24)
#params are usually set automatically in the controller
Person.new(params)
The above will raise the exception
Person.new(params.permit(:name))
This will create a person with name 'Bob', the log output will also contain:
Unpermitted parameters: age
They are logged into DEBUG level: https://github.com/rails/strong_parameters/blob/master/lib/strong_parameters/log_subscriber.rb