web-dev-qa-db-fra.com

POST 422 (Entité non traitable) dans Rails? En raison des routes ou du contrôleur?

J'essaie de donner aux utilisateurs de mon site Web des "points" ou des "crédits" pour avoir tweeté sur le nom de la marque.

J'ai le widget Twitter de fantaisie sur la vue appropriée ...

<p><a  href="https://Twitter.com/share" class="Twitter-share-button" data-text="Check Out This Awesome Website Yay" data-via="BrandName" data-hashtags="ProductName">Tweet</a>
<div id="credited"></div>
<script>window.twttr = (function (d, s, id) {
  var t, js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src= "https://platform.Twitter.com/widgets.js";
  fjs.parentNode.insertBefore(js, fjs);
  return window.twttr || (t = { _e: [], ready: function (f) { t._e.Push(f) } });
}(document, "script", "Twitter-wjs"));
</script>    

J'ai le JS tout écrit et joli ...

function creditTweet() {
  $.post(
    "/credit_Tweet",
    {},
    function(result) {
      var text;
      if (result.status === "noop") {
        text = "Thanks for sharing already!";
      } else if (result.status === "ok") {
        text = "5 Kredit Added";
      }
      $("#credited").html(text);
    }
  );
}

$(function() {
  twttr.ready(function (twttr) {
    window.twttr.events.bind('Tweet', creditTweet);
  }); 
});

Maintenant, le problème est soit dans le contrôleur OR dans les routes (où je poste). Je pense que les routes sont très bien parce que le POST fonctionne presque) , car il s'agit de la description de l'erreur sur wikipedia - "422 Unprocessable Entity (WebDAV; RFC 4918) La demande était bien formée mais n'a pas pu être suivie en raison d'erreurs sémantiques."

Alors, voyez-vous quelque chose de mal avec mon code Ruby dans le contrôleur?

class SocialKreditController < ApplicationController
    Tweet_CREDIT_AMOUNT = 5

  def credit_Tweet
    if !signed_in?
      render json: { status: :error }
    elsif   current_user.Tweet_credited
        Rails.logger.info "Not crediting #{ current_user.id }"
        render json: { status: :noop }
      else
        Rails.logger.info "Crediting #{ current_user.id }"
        current_user.update_attributes Tweet_credited: true
        current_user.add_points Tweet_CREDIT_AMOUNT
        render json: { status: :ok }
      end
  end
end

Et dans mes itinéraires.rb, c'est assez simple, donc je doute qu'il y ait quelque chose de mal ici ...

  get 'social_kredit/credit_Tweet'
  post '/credit_Tweet' => 'social_kredit#credit_Tweet'

Où oh où est cette erreur? Je ne connais clairement pas les requêtes HTTP.

24
piratetone

Je l'ai fait fonctionner!

J'ai ajouté un ...

skip_before_action :verify_authenticity_token

au contrôleur.

Le problème a été détecté lors de l'extraction des journaux et du fait que le jeton CSRF n'a pas pu être vérifié.

52
piratetone

ihaztehcodez (qui était actif pour la dernière fois en 2016, cela ne l'aidera donc pas à lui donner un coup de pouce) mentionne que le skip_before_action :verify_authenticity_token la technique n'est pas aussi sûre car vous perdez la protection contre la contrefaçon.

ils mentionnent que la meilleure/sécurisée/'meilleure pratique', les solutions sont mentionnées ici AVERTISSEMENT: ne peut pas vérifier l'authenticité des jetons CSRF Rails

par exemple.

$.ajaxSetup({
  headers: {
    'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
  }
});

ou

$.ajax({ url: 'YOUR URL HERE',
  type: 'POST',
  beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))},
  data: 'someData=' + someData,
  success: function(response) {
    $('#someDiv').html(response);
  }
});

ou

mettre cela dans une demande ajax

headers: {
  'X-Transaction': 'POST Example',
  'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
0
barlop

Même problème que j'ai rencontré. Il trie après l'ajout

skip_before_action: verify_authenticity_token

en haut de votre contrôleur où votre JS appelle ou envoie des données.

class UserController < ApplicationController
    skip_before_action :verify_authenticity_token
    def create
    end
end

comme indiqué dans l'extrait de code.

0
Shekhar Patil

Si vous incluez Rails meta data dans l'en-tête HTML avec <%= csrf_meta_tags %> cela va générer ce qui suit.

<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="ihwlaOLL232ipKmWYaqbSZacpJegQqooJ+Cj9fLF2e02NTQw7P/MfQyRuzruCax2xYWtEHWsb/uqiiZP6NWH+Q==" />

Vous pouvez extraire le jeton CRSF des métadonnées et le transmettre à votre demande asynchrone. En utilisant la méthode native js fetch, vous pouvez la passer en tant que x-csrf-token entête.

Il s'agit d'un gestionnaire onSave réduit pour un composant React qui améliore un formulaire standard Rails.

  onSaveHandler = (event) => {
    const data = "Foo Bar";
    const metaCsrf = document.querySelector("meta[name='csrf-token']");
    const csrfToken = metaCsrf.getAttribute('content');
    fetch(`/posts/${this.props.post_id}`, {
      method: "PUT",
      body: JSON.stringify({
        content: data
      }),
      headers: {
        'x-csrf-token': csrfToken,
        'content-type': 'application/json',
        'accept': 'application/json'
      },
    }).then(res => {
      console.log("Request complete! response:", res);
    });
  }

La protection contre la contrefaçon est une bonne idée. De cette façon, nous restons en sécurité et ne plaisante pas avec notre configuration Rails.

En utilisant gem 'Rails', '~> 5.0.5' & "react": "^16.8.6",

0
Lex