简体   繁体   中英

Rails Forms and Custom Ajax Calls to a Different Controller

I have 3 Models, Channel, Tag and then Channel Tags, they have a has many through relationship which is set up as so:

Channel Model

has_many :tags, :through => :channel_tags, :dependent => :destroy
has_many :channel_tags, :dependent => :destroy

Tag Model

has_many :channel_tags, :dependent => :destroy
has_many :channels, :through => :channel_tags, :dependent => :destroy

Channel Tags Model

belongs_to :channel
belongs_to :tag

On my Edit Channel Form I have a text input for the user to enter a tag and then a custom js plugin that makes an ajax call to the database to check for existing tags that match the search, if no results are found, the user can add the search term as a new tag, classic functionality for any blogging platform. However I am having some problems with adding a new tag. I have the following JS to make a post:

var name = _ts.$input.val(),
    auth_token = $('input[name="authenticity_token"]').val();

$.post('/tags/?&authenticity_token=' + auth_token, { name : name }, function(data) {
     console.log(data);
});

When I first did this, I was getting errors that it was an invalid authenticity_token, I am assuming this is because it is because the code is for an edit channel form and not a new tag form. I read a suggestion to add the following to the tag controller:

protect_from_forgery with: :null_session

That worked although I am not sure it is the best solution?

But now I am getting a 400 error saying:

ActionController::ParameterMissing in TagsController#create

param is missing or the value is empty: tag

I am pretty confident this is because of the following in my Tags Controller:

 def tag_params
    params.require(:tag).permit(:name,
                                :slug
    )
  end

I am however unsure how to work around it? Is there a special method for interacting with rails with custom JS? I have read the documentation around using the form_for with remote but that is not applicable to what I am trying to do.

Any advice or guidance would be greatly appreciated!!

Many thanks David

First of all, you should get your authenticity token from meta tag (from header), not from hidden input, because the token is always present in header. Then you should setup AJAX calls, so that X-CSRF-Token header will be sent with all your requests:

$.ajaxSetup({
  beforeSend: function(xhr) {
    var token = $('meta[name="csrftoken"]').attr('content');
    xhr.setRequestHeader('X-CSRF-Token', token);
  }
}); 

Now you can keep original protect_from_forgery method. I don't think it's a good idea to use protect_from_forgery with: :null_session here. You should then implement other authorization mechanism.

As to your parameters, based on the request:

$.post('/tags', { name : name }, function(data) {
  console.log(data);
});

Params which TagsController#create receives, will be {name: 'tag name'} . So params.require(:tag) will surely be missing. You should use; params.permit(:name) instead. But, I think, it's better again, to follow Rails defaults and change your AJAX call instead:

$.post('/tags', { tag: { name : name } }, function(data) {
  console.log(data);
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM