Rémi JUHE
Rémi JUHE

Reputation: 405

Headers setting for AMP form in Rails

My AMP form in Rails is returning this error in the terminal :

Completed 406 Not Acceptable in 338ms (ActiveRecord: 54.1ms)
ActionController::UnknownFormat (InscriptionsController#create is missing a template for this request format and variant.
request.formats: ["application/json"]
request.variant: []):

And in the browser :

POST http://localhost:3000/inscriptions?__amp_source_origin=http%3A%2F%2Flocalhost%3A3000 406 (Not Acceptable)
Response must contain the AMP-Access-Control-Allow-Source-Origin header
Form submission failed: Error: Response must contain the AMP-Access-Control-Allow-Source-Origin header​​​
at bb.f.assert (https://cdn.ampproject.org/v0.js:21:319)
at y (https://cdn.ampproject.org/v0.js:26:213)
at https://cdn.ampproject.org/v0.js:179:339

However I did follow the CORS sample code provided by the official documentation https://amp.dev/documentation/guides-and-tutorials/learn/amp-caches-and-cors/amp-cors-requests?referrer=ampproject.org, and according to the AMP validation, everything is fine,

This is my controller :

def create
  @inscription = Inscription.new(inscription_params)
  @inscription.save
  subscriber_email = inscription_params[:email].downcase
  if Subscriber.where(email: subscriber_email).count == 0
    @subscriber = Subscriber.new
    @subscriber.email = subscriber_email
    @subscriber.save
    @new_subscriber = true
  else
    @subscriber = Subscriber.where(email: subscriber_email).first
    @new_subscriber = false
  end
 [...]
 respond_to do |format|
  format.html { redirect_to root_path, notice: "Merci ! Nous avons bien reçu votre inscription !" }
  format.js
  format.json {
    allowed_origins = ["https://example.com", "https://example.com.cdn.ampproject.org/", "http://example.com.amp.cloudflare.com", "https://cdn.ampproject.org"]
    allowed_source_origin = "https://example.com"
    source_origin = params[:__amp_source_origin]
    origin = request.headers["Origin"]
    response.set_header('Content-type', 'application/json')
    response.set_header('Access-Control-Allow-Credentials', 'true')
    response.set_header('Access-Control-Allow-Origin', origin)
    response.set_header('AMP-Access-Control-Allow-Source-Origin', source_origin)
    p response.headers
  }
  end
end

May you help me with this? I probably did something wrong with the headers.

Upvotes: 2

Views: 664

Answers (1)

asimhashmi
asimhashmi

Reputation: 4378

I think the main issue here is not about unknown format, it's about template

In the error you showed, it is clear that you are sending the proper Content-Type in your request

request.formats: ["application/json"]

And you've specified format.json in your controller action.

So the only thing that comes to mind is that there is an issue with the response of your request. Now again looking at the error message, it says you are missing a template.

ActionController::UnknownFormat (InscriptionsController#create is missing a template for this request format and variant

The reason for this is that you are not returning any json response from the controller action

format.json {
    allowed_origins = ["https://example.com", "https://example.com.cdn.ampproject.org/", "http://example.com.amp.cloudflare.com", "https://cdn.ampproject.org"]
    allowed_source_origin = "https://example.com"
    source_origin = params[:__amp_source_origin]
    origin = request.headers["Origin"]
    response.set_header('Content-type', 'application/json')
    response.set_header('Access-Control-Allow-Credentials', 'true')
    response.set_header('Access-Control-Allow-Origin', origin)
    response.set_header('AMP-Access-Control-Allow-Source-Origin', source_origin)
    p response.headers
  }

You need to either render json directly from your controller action or if you don't do that then

Rails tries to find an appropriate template for your controller action.

and I think this is the main reason for this error.

Solution:

1. Add a render statement to your controller action

In that case you can do something like this:

format.json {
    allowed_origins = ["https://example.com", "https://example.com.cdn.ampproject.org/", "http://example.com.amp.cloudflare.com", "https://cdn.ampproject.org"]
    allowed_source_origin = "https://example.com"
    source_origin = params[:__amp_source_origin]
    origin = request.headers["Origin"]
    response.set_header('Content-type', 'application/json')
    response.set_header('Access-Control-Allow-Credentials', 'true')
    response.set_header('Access-Control-Allow-Origin', origin)
    response.set_header('AMP-Access-Control-Allow-Source-Origin', source_origin)
    p response.headers

    render json: {}, status: :ok
  }

2. Create appropriate view file so that Rails can find it

Rails will try to find a view file with as name as controller action in directory name of controller name. So in your case since the name of controller is InscriptionsController so your file should be

app/views/inscriptions/create.json

Suggestion

In the link you provided, it is stated

For requests from the allowed origins, our response will contain the following headers:

Access-Control-Allow-Origin:

AMP-Access-Control-Allow-Source-Origin:

Access-Control-Expose-Headers: AMP-Access-Control-Allow-Source-Origin

But you are not setting the Access-Control-Expose-Headers in your create action which should be set in order for client to read additional response headers in CORS request.

Upvotes: 4

Related Questions