1

I am working on a rails app. I have a listings form which creates the listings. There are no validations while creating the listings form other than on some basic fields. But I wont let the users publish the listings if any of the fields are not filled up. In their dashboard I am showing all their listings.

But how can I find the listings with unfilled database fields??..so that I can show it in a different uncompleted listings tab for them to fill out later..The listing model has_many relation with a photos table.

Update as per Rich Peck's answer

For the enum I added a status field to my listing table with default value 0 and its showing published and draft listings as expected on my existing listings. But I cant create new records now..

Getting below error now while updating records

undefined method `draft?' for "draft":String

I think this validation is causing the error

validates :bed_room, :bath_room, :listing_name, :summary, :building_name, presence: true, unless: "status.draft?"
Abhilash
  • 2,864
  • 3
  • 33
  • 67

2 Answers2

2

If you wanted to keep your current flow, you'll have to pick through any records in the database which might be nil (difficult):

#Controller
@listings = current_user.listings.unfinished

#app/models/listing.rb
class Listing < ActiveRecord::Base
   def self.unfinished
    execute(";WITH XMLNAMESPACES('http://www.w3.org/2001/XMLSchema-  instance' as ns) SELECT * FROM Listings WHERE  (SELECT Listings.*
    FOR xml path('row'), elements xsinil, type
    ).value('count(//*[local-name() != "colToIgnore"]/@ns:nil)', 'int') > 0")          
   end
end

I have absolutely no idea if the above will work. It uses execute in ActiveRecord to use a pure SQL query.


wont let the users publish the listings

This sounds like you want to make draft functionality.

I would strongly recommend putting validations into your model so that you don't have to pick through a database that might have null values dotted around.

I know you said you have this already; I would make the validations conditional on whether the status of the listing is to be "published" or not (with an enum)...

#app/models/listing.rb
class Listing < ActiveRecord::Base
   enum status: [:draft, :published] #-> defaults to draft
   belongs_to :user 
   has_many   :photos

   scope :draft,     -> { where status: :draft     }
   scope :published, -> { where status: :published } 

   ####

   validates :name, :user, :photos, :etc, :etc, presence: true, unless: "status.draft?"

   ####

   def publish!
      self.update status: :published
   end
end

This would work similarly to the Wordpress "draft" functionality (IE publishing and saving are two completely different things):

#config/routes.rb
resources :listings do
    post :publish, on: :member #-> url.com/listings/:id/publish
end

#app/controllers/listings_controller.rb
class ListingsController < ApplicationController
    def new
       @listing = current_user.listings.new
    end

    def create
       @listing = current_user.listings.new listing_params
       @listing.save #-> will be "draft" by default so no validations
    end

    def publish
       @listing = current_user.listings.find params[:id]
       redirect_to @listing if @listing.publish!
    end
end

In your front-end, you'll be able to then list the @listings by whether they're published or draft:

#app/views/listings/index.html.erb
<% @listings.published do |published| %>
    ...
<% end %>

<% @listings.draft do |draft| %>
   ...
<% end %>

Update

According to the OP, the answer was to use the following in his model:

#app/models/listing.rb
class Listing < ActiveRecord::Base
   enum status: [:draft, :published] #-> defaults to draft
   belongs_to :user 
   has_many   :photos

   ####

   validates :name, :user, :photos, :etc, :etc, presence: true, unless: "draft?"

   ####

   def publish!
      self.update status: :published
   end
end
Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • Exactly..This is what I was looking for..Will try this and let you know. Thanks a lot.. – Abhilash Jan 01 '16 at 12:06
  • 1
    Thanks man; don't hold me to the top one - the bottom one is what I'd go for ([convention over configuration](https://en.wikipedia.org/wiki/Convention_over_configuration)) – Richard Peck Jan 01 '16 at 12:13
  • I followed the similar pattern as u mentioned. But am getting an error. I added an update to the question with the error. Thank you. – Abhilash Jan 02 '16 at 22:01
  • 1
    Fixed the error by just doing "draft?" instead of "status.draft". Also I think there is no need to define scopes as its automatically done when using enums.If you dont mind it will be great if you can update your answer with this fix. Thank you.. :) – Abhilash Jan 03 '16 at 07:11
1

Assuming Listing is your model name and required_field is a unfilled field name,

Listing.where(required_field: nil).where(user: current_user)

will give the listings of the current user with unfilled fields.

listings.includes(:photos).where(photos: { id: nil })

Raj
  • 22,346
  • 14
  • 99
  • 142