14
votes

We want to use our content editable, taking advantage of the generated routes with the following in router.ex:

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end
  scope "/", TextEditor do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
    resources "/posts", PostController
  end

and the controller functions, namely create:

  def create(conn, %{"post" => post_params}) do
    changeset = Post.changeset(%Post{}, post_params)

    case Repo.insert(changeset) do
      {:ok, _post} ->
        conn
        |> put_flash(:info, "Post created successfully.")
        |> redirect(to: post_path(conn, :index))
      {:error, changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end

However we don't want to use the generated form, we are then attempting to test this with divs and the jquery method $.post:

<div id="newPost" contenteditable="true">write here</div>
<div id="button" class="btn btn-primary">Save</div>

<script type="text/javascript">
$(document).ready(function(){
  $("#button").click(function() {
    var post = $("#newPost").html();

    $.post( "/posts/post", { title: post })
     .done(function() {
        alert( "Data Loaded: " );
    });
  });
});
</script>

However we are not getting the alert or any data inserted into our database. What are we missing?

EDIT: In the browser pipeline we removed the cross forgery plug because of a csrf token error.

1
Do you get any error in your console? Could you please post your browser pipeline?Gazler
No errors. In the console we get: [info] POST /posts/post. I added the browser pipeline to the question. We removed the cross forgery plug because of the csrf token error.mesosteros
Not that you should do this as a solution, but could you check if it works if you remove :put_secure_browser_headers?Gazler
I tested and it does not work by removing it.mesosteros
We also had a problem with params which is why we added "post" to "/posts/" ("/posts/post").mesosteros

1 Answers

22
votes

Try the following:

$.post( "/posts", { post: { title: post } })

Your controller expects the parameters to be nested under a key of post

def create(conn, %{"post" => post_params}) do

I wouldn't recommend doing so, but you can change your controller to:

def create(conn, %{} = post_params) do

To look for parameters without the root post key. However having the post key means you can have additional parameters unrelated to the form easily.

I also would not recomment disabling the CSRF check. You can submit with the CSRF token easily by storing it in a meta tag:

<meta name="csrf" content="<%= Plug.CSRFProtection.get_csrf_token() %>">

And then adding it as a header to your post request:

var csrf = document.querySelector("meta[name=csrf]").content;

$.ajax({
    url: "/posts",
    type: "post",
    data: {
      post: { title: post } })
    },
    headers: {
        "X-CSRF-TOKEN": csrf 
    },
    dataType: "json",
    success: function (data) {
      console.log(data);
    }
});