Rails 5 RC1 - POST attributes not available in params - ruby-on-rails-5

I'm sending a POST request to a Rails 5 RC1 api to create a new vote record. I can see from request.raw_post that the attributes are included in the POST request, but they do not make it into params. I've attempted to permit the attributes with no success.
# article_votes_controller.rb
def article_vote_params
logger.debug "### hello from the params function"
logger.debug request.raw_post
params.permit(:user_id, :user_type, :article_id, :article_type)
logger.debug params.inspect
logger.debug params.to_unsafe_h
end
The above code gives the following output.
### hello from the params function
{"user_id":"1","user_type":"User","article_id":"99","article_type":"Article"}
<ActionController::Parameters {"controller"=>"article_votes", "action"=>"create"} permitted: true>
{"controller"=>"article_votes", "action"=>"create"}
Why wouldn't attributes that are included in the request be included in params?

IIRC the permit method returns a new instance of params, so if you did
p = params.permit(:user_id, :user_type, :article_id, :article_type)
logger.debug p.inspect
You would see the correctly, whitelisted params.

Related

How can I add custom header parameters to a API GET call in clojurescript

I'm building a demo application in clojurescript with KeeFrame and to retrieve a part of the information for this website I need to call an external API which requires a custom HTTP header parameter in the GET requests
I'm using re-frame.core for the API calls, which uses ajax.core.
I also tried to replace this with cljs-http.client. However the result is the same.
I already managed to add custom header parameters to the request header by using clj-http at server site. But this is not a solution I want to implement for this website because that means that I first have to rebuild the API I'm calling. So I can use it from my clojurescript without the parameter.
This code works. A correct GET request is generated
{:http-xhrio {
:method :get
:uri (str transuri "/acquirer/" 673072009 "/acquirerref/" acquirerRefNo)
:headers {"Accept" "application/json"}
:response-format (http/json-response-format {:keywords? true})
:on-failure [:common/set-error]}}
With "Accept: application/json" as a request header
This code does not work. Instead of a GET request an OPTIONS request is generated
{:http-xhrio {
:method :get
:uri (str transuri "/acquirer/" 673072009 "/acquirerref/" acquirerRefNo)
:headers {"Accept" "application/json" "Custom" "Value"}
:response-format (http/json-response-format {:keywords? true})
:on-failure [:common/set-error]}}
And in the request header "Accept: application/json" is not visible but "Access-Control-Request-Headers: custom" is
I expected a GET request with "Accept: application/json" and "Custom: Value" in the request header.
Can someone tell me what I'm doing wrong or provide me with a link with information about this?
Thanks in advance
The Browser will send a "preflight" OPTIONS request to verify that it is allowed to send the "Custom" request header. The server is supposed to approve by replying with "Access-Control-Allow-Headers".
See https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
I have not used KeeFrame, but I have a working example using a new re-frame lib I'm working on. It invokes an ajax request using this interceptor:
(def ajax-intc
"Interceptor for performing AJAX requests"
(interceptor
{:id :ajax-intc
:enter identity
:leave (fn [ctx] ; #todo (with-result ctx ...)
(let [ajax (:ajax ctx)]
;(t/spyx :ajax-intc-start ctx)
;(t/spyx :ajax-intc-start ajax)
(when-not (nil? ajax)
(t/spy :awt-ajax-intc--ajax ajax)
(let [method (t/grab :method ajax)
uri (t/grab :uri ajax)
ajax-opts-present (set/intersection (set (keys ajax)) ajax-options-keys)
opts-map (t/submap-by-keys ajax ajax-opts-present)]
;(t/spy :ajax-intc-ready (t/vals->map method uri opts-map))
(condp = method
:get (do
(t/spy :awt-ajax-intc--opts-map opts-map)
(ajax/GET uri opts-map))
:put (ajax/PUT uri opts-map)
:post (ajax/POST uri opts-map)
(throw (ex-info "ajax-intc: unrecognized :method" ajax))))))
ctx)}))
When invoked with this event:
(flame/dispatch-event [:ajax-demo :get "/fox.txt"
{:handler ajax-handler
:error-handler ajax-error-handler
:headers {"custom" "something"}
}])
one can see in the Chrome dev console that the headers come through:
:awt-localstore-load-intc--loaded-value-1 {}
core.cljs:192 :awt-ajax-intc--ajax => {:method :get, :uri "/fox.txt", :handler #object[flintstones$core$ajax_handler], :error-handler #object[flintstones$core$ajax_error_handler], :headers {"custom" "something"}}
core.cljs:192 :awt-ajax-intc--opts-map => {:handler #object[flintstones$core$ajax_handler], :error-handler #object[flintstones$core$ajax_error_handler], :headers {"custom" "something"}}
If you want to try it out, you can clone this repo: git#github.com:cloojure/cljs-enflame.git
and then run:
lein clean
lein figwheel
and see it run in the browser.

authenticate_or_request_with_http_token never pass

I am trying to implement an authentication for my rails API following this tutorial from railscast. I'm using the method authenticate_or_request_with_http_token, which I should check the token inside the block and it should pass if the block returns true. However, the method never pass even when I just put true in the block. This is what I see in the log:
I am using rails 4.0
Filter chain halted as :restrict_access rendered or redirected
This is my code:
before_filter :restrict_access
def restrict_access
authenticate_or_request_with_http_token do |token, options|
true
end
end
You backend have to supply authentication header. For example - 'Authorization' => "Token token=#{#token}". If method doesn't find the header it returns http status 403:Access forbidden
In case you're using Postman, I got it to work with the following config:
Authorization Type: "API Key"
key: "Authorization"
value: "Token YOUR_TOKEN" (i.e. "Token abcd1234")
Add To: "Header"

No request params in constraint when testing route

When I run this in practice it works, but I can't seem to write a working test for my route constraint with rspec.
When the test runs the constraint is triggered, but the request params are empty, thus it does not validate and the test fails.
I am running Rails 3.0.9, rspec-rails 2.6.1 and rspec 2.6.0.
config/routes.rb
match ":param1-unique-:param2" => "controller#index",
:constraints => ParamConstraint.new
lib/param_constraint.rb
class ParamConstraint
def matches?(request)
#request ||= request
valid_param1? && valid_param2?
end
def valid_param1?
#request.params[:param1] == "lorem"
end
def valid_param2?
#request.params[:param2] == "ipsum"
end
end
spec/routing/param_constraint_spec.rb
require 'spec_helper'
describe "param constraint routing" do
it "recognizes route for param1 and param2" do
{ :get => "/lorem-unique-ipsum" }.
should route_to(
:controller => "controller",
:action => "index",
:param1 => "lorem",
:param2 => "ipsum"
)
end
end
Update
If I inspect the request in the constraint I get the following output:
#<ActionDispatch::Request:0x007fee140ff910 #env={
"rack.version"=>[1, 1],
"rack.input"=>#<StringIO:0x007fee1446da48>,
"rack.errors"=>#<StringIO:0x007fee1446e768>,
"rack.multithread"=>true,
"rack.multiprocess"=>true,
"rack.run_once"=>false,
"REQUEST_METHOD"=>"GET",
"SERVER_NAME"=>"example.org",
"SERVER_PORT"=>"80",
"QUERY_STRING"=>"",
"PATH_INFO"=>"/lorem-unique-ipsum",
"rack.url_scheme"=>"http",
"HTTPS"=>"off",
"SCRIPT_NAME"=>"",
"CONTENT_LENGTH"=>"0"
}>
I ran into this same issue today, searching for an answer brought me to this page's question. For what it's worth, I had to resort to writing a request spec instead.
context "passing params that satisfy ParamConstraint" do
before do
visit "/lorem-unique-ipsum"
end
it "should serve up a page with content" do
# replace this with some assertion that gets satisfied by
# pages served up when ParamConstraint.new.matches? returns true
page.should have_selector("html body div#foo")
page.should_not have_selector("html body div#bar")
end
end
context "passing params that DO NOT satisfy ParamConstraint" do
before do
visit "/other-unique-other"
end
it "should serve up a page with different content" do
# replace this with some assertion that gets satisfied by
# pages served up when ParamConstraint.new.matches? returns false
page.should_not have_selector("html body div#foo")
page.should have_selector("html body div#bar")
end
end
This doesn't answer your question, which I take to be "how to test routing constraint", as the proper way would be via a routing spec. But given this gap in how request.params works when you use "should route_to", this is a workaround. A request spec, as opposed to a routing spec, will fill request.params correctly.
Same issue exists years later, with rspec-core 3.4.4, rspec-rails 3.4.2, rails 4.2.6. Don't have time to dig into exactly why...
You can use a request spec as suggested above, but don't use it to test the page contents. Instead, replicate a routing test (route_to) by checking the conversion of URL paths to request params:
RSpec.describe 'routes', type: :request do
describe '/:slug' do
it 'routes correctly' do
get '/test-product-slug'
expect(request.params).to eq(
'controller' => 'product',
'action' => :index,
'slug' => 'test-product-slug'
)
end
end
end

Error when saving a Backbone.js model with Rails

I have Backbone.js collection and model for a project object:
window.Project = Backbone.Model.extend();
window.Projects = Backbone.Collection.extend({
model: Project,
url: '/projects'
});
I have setup a rails controller to respond to the Backbone.js collection:
class ProjectsController < ApplicationController
def index
render :json => Project.all
end
def create
project = Project.create! params
render :json => project
end
end
Index works fine and I get a list of projects in my web app. The problem is if I try and create a model on the Projects collection I get a 500 error from the server.
The error message on the server is as follows:
Started POST "/projects" for 127.0.0.1 at 2011-08-21 08:27:56 +0100
Processing by ProjectsController#create as JSON
Parameters: {"title"=>"another test"}
Completed 500 Internal Server Error in 16ms
ActiveRecord::UnknownAttributeError (unknown attribute: action):
app/controllers/projects_controller.rb:8:in `create'
I am not sure what the unknown attribute: action is referring to.
For info I have set up the projects_controller as resources :projects. I have also set rails to ActiveRecord::Base.include_root_in_json = false.
Yes, Rails always adds the action and controller to params. The parameters come from ActionDispatch::Http::Parameters:
def parameters
#env["action_dispatch.request.parameters"] ||= begin
params = request_parameters.merge(query_parameters)
params.merge!(path_parameters)
encode_params(params).with_indifferent_access
end
end
And path_parameters:
Returns a hash with the parameters used to form the path of the request. Returned hash keys are strings:
{'action' => 'my_action', 'controller' => 'my_controller'}
So you shouldn't be doing project = Project.create! params. You could go the update_attributes route:
project = Project.new
project.update_attributes params[:model_name]
But this assumes that you have what you need in a sub-hash of params and it won't call your validators. Backbone won't namespace your attributes by default but you could override Backbone.sync and do it yourself. Still, you probably want your validations so update_attributes should generally be avoided.
Your best bet is to pull exactly the attributes out of params that you're expecting to be there. This is even the Backbone recommended practise:
*(In real code, never use update_attributes blindly, and always whitelist the attributes you allow to be changed.)*
You can enable parameter wrapping. Add a file in the initializer directory with:
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json]
end
and, for json request, you post params will now be wrapped with the model name.

How do I write a Rails 3.1 engine controller test in rspec?

I have written a Rails 3.1 engine with the namespace Posts. Hence, my controllers are found in app/controllers/posts/, my models in app/models/posts, etc. I can test the models just fine. The spec for one model looks like...
module Posts
describe Post do
describe 'Associations' do
it ...
end
... and everything works fine.
However, the specs for the controllers do not work. The Rails engine is mounted at /posts, yet the controller is Posts::PostController. Thus, the tests look for the controller route to be posts/posts.
describe "GET index" do
it "assigns all posts as #posts" do
Posts::Post.stub(:all) { [mock_post] }
get :index
assigns(:posts).should eq([mock_post])
end
end
which yields...
1) Posts::PostsController GET index assigns all posts as #posts
Failure/Error: get :index
ActionController::RoutingError:
No route matches {:controller=>"posts/posts"}
# ./spec/controllers/posts/posts_controller_spec.rb:16
I've tried all sorts of tricks in the test app's routes file... :namespace, etc, to no avail.
How do I make this work? It seems like it won't, since the engine puts the controller at /posts, yet the namespacing puts the controller at /posts/posts for the purpose of testing.
I'm assuming you're testing your engine with a dummy rails app, like the one that would be generated by enginex.
Your engine should be mounted in the dummy app:
In spec/dummy/config/routes.rb:
Dummy::Application.routes.draw do
mount Posts::Engine => '/posts-prefix'
end
My second assumption is that your engine is isolated:
In lib/posts.rb:
module Posts
class Engine < Rails::Engine
isolate_namespace Posts
end
end
I don't know if these two assumptions are really required, but that is how my own engine is structured.
The workaround is quite simple, instead of this
get :show, :id => 1
use this
get :show, {:id => 1, :use_route => :posts}
The :posts symbol should be the name of your engine and NOT the path where it is mounted.
This works because the get method parameters are passed straight to ActionDispatch::Routing::RouteSet::Generator#initialize (defined here), which in turn uses #named_route to get the correct route from Rack::Mount::RouteSet#generate (see here and here).
Plunging into the rails internals is fun, but quite time consuming, I would not do this every day ;-) .
HTH
I worked around this issue by overriding the get, post, put, and delete methods that are provided, making it so they always pass use_route as a parameter.
I used Benoit's answer as a basis for this. Thanks buddy!
module ControllerHacks
def get(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "GET")
end
# Executes a request simulating POST HTTP method and set/volley the response
def post(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "POST")
end
# Executes a request simulating PUT HTTP method and set/volley the response
def put(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "PUT")
end
# Executes a request simulating DELETE HTTP method and set/volley the response
def delete(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "DELETE")
end
private
def process_action(action, parameters = nil, session = nil, flash = nil, method = "GET")
parameters ||= {}
process(action, parameters.merge!(:use_route => :my_engine), session, flash, method)
end
end
RSpec.configure do |c|
c.include ControllerHacks, :type => :controller
end
Use the rspec-rails routes directive:
describe MyEngine::WidgetsController do
routes { MyEngine::Engine.routes }
# Specs can use the engine's routes & named URL helpers
# without any other special code.
end
– RSpec Rails 2.14 official docs.
Based on this answer I chose the following solution:
#spec/spec_helper.rb
RSpec.configure do |config|
# other code
config.before(:each) { #routes = UserManager::Engine.routes }
end
The additional benefit is, that you don't need to have the before(:each) block in every controller-spec.
Solution for a problem when you don't have or cannot use isolate_namespace:
module Posts
class Engine < Rails::Engine
end
end
In controller specs, to fix routes:
get :show, {:id => 1, :use_route => :posts_engine}
Rails adds _engine to your app routes if you don't use isolate_namespace.
I'm developing a gem for my company that provides an API for the applications we're running. We're using Rails 3.0.9 still, with latest Rspec-Rails (2.10.1). I was having a similar issue where I had defined routes like so in my Rails engine gem.
match '/companyname/api_name' => 'CompanyName/ApiName/ControllerName#apimethod'
I was getting an error like
ActionController::RoutingError:
No route matches {:controller=>"company_name/api_name/controller_name", :action=>"apimethod"}
It turns out I just needed to redefine my route in underscore case so that RSpec could match it.
match '/companyname/api_name' => 'company_name/api_name/controller_name#apimethod'
I guess Rspec controller tests use a reverse lookup based on underscore case, whereas Rails will setup and interpret the route if you define it in camelcase or underscore case.
It was already mentioned about adding routes { MyEngine::Engine.routes }, although it's possible to specify this for all controller tests:
# spec/support/test_helpers/controller_routes.rb
module TestHelpers
module ControllerRoutes
extend ActiveSupport::Concern
included do
routes { MyEngine::Engine.routes }
end
end
end
and use in rails_helper.rb:
RSpec.configure do |config|
config.include TestHelpers::ControllerRoutes, type: :controller
end