0

In my Post.rb model, I am doing this:

validates_presence_of :body

In my controller I have this action that I am executing:

  def mark_as_published
    if @post.unpublished?
      @post.published!
      redirect_to post_path(@post), notice: "Successfully published."
    else
      redirect_to post_path(@post), notice: "Post already published"
    end
  end

This is the error I am getting:

app/controllers/posts_controller.rb:104:in `mark_as_published'
Started PUT "/posts/ebola-death-climbs-past-6-000/mark_as_published" for 67.230.41.168 at 2014-12-10 20:15:29 +0000
 app[web.1]: ActiveRecord::RecordInvalid (Validation failed: Body can't be blank):

This is the record in the console:

> Post.last
=> #<Post id: 29, title: "Ebola death climbs past 6,000", photo: nil, body: "Fresh figures from WHO has revealed that the death...", created_at: "2014-12-10 20:08:58", updated_at: "2014-12-10 20:08:58", user_id: 10, ancestry: nil, file: nil, status: 2, slug: "ebola-death-climbs-past-6-000", publication_status: 0, has_eyewitness: false, youtube_embed_code: "", soundcloud_embed_code: "">

Why does this validation fail, only on the save/update, even though the post.body is not blank?

Edit 1

The publication_status is just an enum:

enum publication_status: [ :unpublished, :published ]

Which comes with a set of handy methods, including published?, unpublished?, published!, and unpublished!. The latter two basically toggle the value to be the flag, i.e. unpublished! changes the publication_status to be unpublished and vice versa.

Here are other validations on the Post.rb model:

  validates_length_of :body, maximum: 150, too_long: 'The report must be less than 150 words.',
                        tokenizer: ->(str) { str.scan(/\w+/) }
  validates_length_of :title, maximum: 7, too_long: 'The title must be less than 7 words.',
                                              tokenizer: ->(str) { str.scan(/\w+/) }

Edit 2

This is what happens when I mark the record as published in the console:

0> p = Post.last
=> #<Post id: 29, title: "Ebola death climbs past 6,000", photo: nil, body: "Fresh figures from WHO has revealed that the death...", created_at: "2014-12-10 20:08:58", updated_at: "2014-12-10 20:08:58", user_id: 10, ancestry: nil, file: nil, status: 2, slug: "ebola-death-climbs-past-6-000", publication_status: 0, has_eyewitness: false, youtube_embed_code: "", soundcloud_embed_code: "">
irb(main):002:0> p.published!
=> true
irb(main):003:0> p.save
=> true

No SQL is generated. Not sure if this is because I am doing this in production on Heroku.

Edit 3

I tried to publish a record in development, and this is the SQL & server log:

Started PUT "/posts/longword-verylongword-longword-longword-longword-vellylongword-prettylongword/mark_as_published" for 127.0.0.1 at 2014-12-10 19:22:56 -0500
Processing by PostsController#mark_as_published as HTML
  Parameters: {"authenticity_token"=>"8kYDxjYS54sGozjSS4ZZwQFJUTtIBgLpEmpAlTRZc4k=", "id"=>"longword-verylongword-longword-longword-longword-vellylongword-prettylongword"}
  User Load (1.1ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = 1  ORDER BY "users"."id" ASC LIMIT 1
   (2.0ms)  SELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)))  [["user_id", 1]]
   (1.2ms)  SELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'editor') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)))  [["user_id", 1]]
   (0.2ms)  BEGIN
   (0.2ms)  ROLLBACK
Completed 422 Unprocessable Entity in 62ms

ActiveRecord::RecordInvalid - Validation failed: Body can't be blank:

When I do it in the console, this is the log:

> p = Post.last
  Post Load (0.6ms)  SELECT  "posts".* FROM "posts"   ORDER BY "posts"."id" DESC LIMIT 1
=> #<Post id: 37, title: "LongWord VeryLongWord LongWord LongWord LongWord V...", photo: nil, body: "10PP gives you a lot of one on one attention that ...", created_at: "2014-11-27 09:21:06", updated_at: "2014-11-27 09:21:06", user_id: nil, ancestry: nil, file: nil, status: 1, slug: "longword-verylongword-longword-longword-longword-v...", publication_status: 0, has_eyewitness: false, youtube_embed_code: "", soundcloud_embed_code: "">
[21] pry(main)> p.published!
   (0.2ms)  BEGIN
  SQL (2.0ms)  UPDATE "posts" SET "publication_status" = $1, "updated_at" = $2 WHERE "posts"."id" = 37  [["publication_status", 1], ["updated_at", "2014-12-11 00:24:18.419390"]]
  FriendlyId::Slug Load (1.9ms)  SELECT  "friendly_id_slugs".* FROM "friendly_id_slugs"  WHERE "friendly_id_slugs"."sluggable_id" = $1 AND "friendly_id_slugs"."sluggable_type" = $2  ORDER BY "friendly_id_slugs".id DESC LIMIT 1  [["sluggable_id", 37], ["sluggable_type", "Post"]]
   (0.9ms)  COMMIT
=> true
marcamillion
  • 32,933
  • 55
  • 189
  • 380
  • Start a console and run `@post.published!` for `@post=Post.last`... Please, paste here the resulting SQL statement – Ruby Racer Dec 10 '14 at 22:15
  • So, you are saving in the console, but not in the action... And no SQL, as you say... I can't help.. Maybe if you have some locally mirrored development environment? Or the `published!` definition? Anything? – Ruby Racer Dec 10 '14 at 23:29
  • @RubyRacer - I did it in development and updated the question with the SQL statements. There is no `published!` definition, because it is a Rails 4 feature - http://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html – marcamillion Dec 11 '14 at 00:25

2 Answers2

1

From the log I can see clearly you do not retrieve the Post from the database. So you are saving a "new/empty" post. Please verify how your @post variable is set. I am guessing you are using the incorrect before_action now, or your post retrieval is too liberal and defaults to a new post if not found?

nathanvda
  • 49,707
  • 13
  • 117
  • 139
  • Can you take a look at this CanCanCan related question for me please - http://stackoverflow.com/questions/27413309/how-do-i-setup-my-cancancan-permissions-correctly – marcamillion Dec 11 '14 at 15:42
0

One option, if and only if it works within your application's logic, is to limit the validation to creates:

validates_presence_of :body, on: :create 

If your app's logic dictates that updates need to run the validation, it would be helpful to see more code in order to better know how @post is populated, what the published/unpublished? methods look like, etc.

craig.kaminsky
  • 5,588
  • 28
  • 31
  • I need that validation to pass on creation, edit & update (i.e. the default options). I updated the question with details on `published/unpublished` which are just enums, so the stock methods are what it comes with. – marcamillion Dec 10 '14 at 20:46