samedi 17 juin 2017

Ember and Rails, Parameters: {... "post_id"=>nil}} Nil?! Except sometimes not.

I'm working on posting and deleting comments on an Ember/Rails blog. When I log in, I can post and delete depending on who signed in, so I can't delete others posts. However when I try to add and delete comments to these posts I can only add or delete comments that are attached to a post that the current user owns BUT once I've commented on a post that I own, then I can go to other users posts and interact normally. I'm guessing this has something to do with Ember caching my user id and sending it after it's managed to send it once, but I'm not sure. Here's what what I hope are all the relevant files.

class CommentsController < OpenReadController
  before_action :set_comment, only: [:show, :update, :destroy]
  before_action :authenticate, only: [:create, :update, :destroy]
  # GET /comments
  def index
    @comments = Comment.all

    render json: { comments: Comment.all }, methods: :post_id
  end

  # GET /comments/1
  def show
    render json: { comment: @comment }, methods: :post_id
  end

  # POST /comments
  def create
    @comment = current_user.comments.new(comment_params)

    if @comment.save
      render json: { comment: @comment }, methods: :post_id, status: :created, location: @comment
    else
      render json: @comment.errors, status: :unprocessable_entity
    end
  end

  # PATCH/PUT /comments/1
  def update
    if @comment.update(comment_params)
      render json: @comment
    else
      render json: @comment.errors, status: :unprocessable_entity
    end
  end

  # DELETE /comments/1
  def destroy
    @comment.destroy
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_comment
      @comment = Comment.find(params[:id])
    end

    # Only allow a trusted parameter "white list" through.
    def comment_params
      params.require(:comment).permit(:author, :body, :post_id)
    end

``` The above inherits from here

# frozen_string_literal: true
# Inherit from this class to allow unauthenticate access to read actions
class OpenReadController < ProtectedController
  READ_ACTIONS = [:index, :show].freeze
  skip_before_action :authenticate, only: READ_ACTIONS
  before_action :set_current_user, except: READ_ACTIONS
end

```

class PostsController < OpenReadController
  before_action :set_post, only: [:show, :update, :destroy]
  before_action :authenticate, only: [:create, :update, :destroy]

  # GET /posts
  def index
    @posts = Post.all

    render json: { posts: Post.all, comments: Comment.all }
  end

  # GET /posts/1
  def show
    render json: { post: @post, comments: @post.comments }
  end

  # POST /posts
  def create
    @post = current_user.posts.new(post_params)
    if @post.save
      render json: { post: @post, comments: @post.comments }, methods: :comment_ids, status: :created, location: @post
    else
      render json: @post.errors, status: :unprocessable_entity
    end
  end

  # PATCH/PUT /posts/1
  def update
    if @post.update(post_params)
      render json: @post
    else
      render json: @post.errors, status: :unprocessable_entity
    end
  end

  # DELETE /posts/1
  def destroy
    @post.destroy
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_post
      @post = current_user.posts.find(params[:id])
    end

    # Only allow a trusted parameter "white list" through.
    def post_params
      params.require(:post).permit( :title, :body)
    end
end

```

# frozen_string_literal: true
class UsersController < ProtectedController
  skip_before_action :authenticate, only: [:signup, :signin]

  # POST '/sign-up'
  def signup
    user = User.create(user_creds)
    if user.valid?
      render json: user, status: :created
    else
      render json: user.errors, status: :bad_request
    end
  end

  # POST '/sign-in'
  def signin
    creds = user_creds
    if (user = User.authenticate creds[:email],
                                 creds[:password])
      render json: user, serializer: UserLoginSerializer, root: 'user'
    else
      head :unauthorized
    end
  end

  # DELETE '/sign-out/1'
  def signout
    if current_user == User.find(params[:id])
      current_user.logout
      head :no_content
    else
      head :unauthorized
    end
  end

  # PATCH '/change-password/:id'
  def changepw
    if !current_user.authenticate(pw_creds[:old]) ||
       (current_user.password = pw_creds[:new]).blank? ||
       !current_user.save
      head :bad_request
    else
      head :no_content
    end
  end

  def index
    render json: User.all
  end

  def show
    user = User.find(params[:id])
    render json: user
  end

  def update
    head :bad_request
  end

  private

  def user_creds
    params.require(:credentials)
          .permit(:email, :password, :password_confirmation)
  end

  def pw_creds
    params.require(:passwords)
          .permit(:old, :new)
  end

  private :user_creds, :pw_creds
end

```

class Comment < ApplicationRecord
  belongs_to :post
  belongs_to :user
end

```

class Post < ApplicationRecord
  has_many :comments, dependent: :destroy
  belongs_to :user
end

```

# frozen_string_literal: true
class User < ApplicationRecord
  include Authentication
  has_many :posts
  has_many :comments
end

```

ActiveRecord::Schema.define(version: 20170616000945) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "comments", force: :cascade do |t|
    t.string   "author"
    t.text     "body"
    t.integer  "post_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["post_id"], name: "index_comments_on_post_id", using: :btree
  end

  create_table "examples", force: :cascade do |t|
    t.text     "text",       null: false
    t.integer  "user_id",    null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["user_id"], name: "index_examples_on_user_id", using: :btree
  end

  create_table "posts", force: :cascade do |t|
    t.string   "title"
    t.text     "body"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer  "user_id"
    t.index ["user_id"], name: "index_posts_on_user_id", using: :btree
  end

  create_table "user_coins", force: :cascade do |t|
    t.string   "name"
    t.decimal  "price"
    t.integer  "user_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["user_id"], name: "index_user_coins_on_user_id", using: :btree
  end

  create_table "users", force: :cascade do |t|
    t.string   "email",           null: false
    t.string   "token",           null: false
    t.string   "password_digest", null: false
    t.datetime "created_at",      null: false
    t.datetime "updated_at",      null: false
    t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
    t.index ["token"], name: "index_users_on_token", unique: true, using: :btree
  end

  add_foreign_key "comments", "posts"
  add_foreign_key "examples", "users"
  add_foreign_key "posts", "users"
  add_foreign_key "user_coins", "users"
end

Here's an example of a failed post.

Started POST "/comments" for 127.0.0.1 at 2017-06-17 13:55:51 -0400
Processing by CommentsController#create as HTML
  Parameters: {"comment"=>{"author"=>"bob", "body"=>"bob", "post_id"=>nil}}
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."token" = $1 LIMIT $2  [["token", "8a37191b44eb1708db0bb36cf857eed8"], ["LIMIT", 1]]
  CACHE (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."token" = $1 LIMIT $2  [["token", "8a37191b44eb1708db0bb36cf857eed8"], ["LIMIT", 1]]
   (0.2ms)  BEGIN
   (0.2ms)  ROLLBACK
[active_model_serializers] Rendered ActiveModel::Serializer::Null with ActiveModel::Errors (0.08ms)
Completed 422 Unprocessable Entity in 41ms (Views: 29.3ms | ActiveRecord: 0.6ms)

And then after posting to my own comment, I went back to the other users post, and

Started POST "/comments" for 127.0.0.1 at 2017-06-17 13:58:07 -0400
Processing by CommentsController#create as HTML
  Parameters: {"comment"=>{"author"=>"bob", "body"=>"bob", "post_id"=>"46"}}
  User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."token" = $1 LIMIT $2  [["token", "8a37191b44eb1708db0bb36cf857eed8"], ["LIMIT", 1]]
  CACHE (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."token" = $1 LIMIT $2  [["token", "8a37191b44eb1708db0bb36cf857eed8"], ["LIMIT", 1]]
   (0.1ms)  BEGIN
  Post Load (0.1ms)  SELECT  "posts".* FROM "posts" WHERE "posts"."id" = $1 LIMIT $2  [["id", 46], ["LIMIT", 1]]
  SQL (2.0ms)  INSERT INTO "comments" ("author", "body", "post_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["author", "bob"], ["body", "bob"], ["post_id", 46], ["created_at", 2017-06-17 17:58:07 UTC], ["updated_at", 2017-06-17 17:58:07 UTC]]
   (0.4ms)  COMMIT
[active_model_serializers] Rendered ActiveModel::Serializer::Null with Hash (0.52ms)
Completed 201 Created in 12ms (Views: 1.6ms | ActiveRecord: 3.1ms)

I think that's everything! Thanks in advance for the help, this is only my second rails project and my first time using Ember, I'm still not sure how all the pieces fit together so I don't even know how to really trouble shoot this very well. I feel like this is a pretty simple solution, I'm just not seeing it.




Aucun commentaire:

Enregistrer un commentaire