Checkbox for terms and conditions, without column in database - ruby-on-rails

I need a "I accept terms of service" checkbox on a page, it has to be checked in order for the order to proceed. It seems hence illogical to have a column in the database to match this (whether user has accepted or declined terms).
I am using the form helper like this in my view:
<%= check_box("client", "terms") %>
And in my model:
validates_acceptance_of :terms
At the moment it is not working at all.
This seems like a really common piece of code, yet I can't find it used anywhere without having the terms in the model. Else I could use javascript to validate it, but would prefer to keep it all the in model.

This should work fine, without a database column or attr_accessor:
http://guides.rubyonrails.org/active_record_validations.html#acceptance
I would be inclined to check your params hash is as it should be i.e. that the 'terms' attribute is being passed within the 'client' hash, perhaps try adding raise params.inspect on your controller create action to help you debug?

What about having an attr_accessor :terms in your Client model?

I had this working with these settings:
In the controller, I have added :terms_of_service as a permitted field:
def application_params
params.require(:application).permit(. . . , :terms_of_service)
end
In the model:
attr_accessor :terms_of_service
validates :terms_of_service, :acceptance => true
In the view:
<%= f.check_box("terms_of_service", :checked => false) %>

attr_accessor :terms will do the trick nicely.

Either go with #neutrino's solution, or to reset :terms to "not accepted" if you need to redisplay the form (because validation may fail), use this:
def terms
nil
end
def terms=(val)
# do nothing
end

Related

How can I set "If" statement with nil?

country attribute's default value is nil.
In countries table, some record has image_url, and the rest of the record's country attributes are nil.
So I coded this in helper
def image(user)
if user.country.image_url
image_tag "flags/#{user.country.image_url}.png"
end
end
However, it returns error when image_url was nil
Something went wrong
How can I fix?
You'll need two conditions: The user has to have a country, and that country has to have an image_url. Only then will there be something to show. Luckily, it's a simple tweak:
def image(user)
if(user.country && user.country.image_url)
image_tag "flags/#{user.country.image_url}.png"
end
end
If you're paranoid, you should make sure that user isn't nil either.
Hope that helps!
While method chaining like that certainly works, your code will look a lot cleaner and become less coupled if you implement some method delegation.
Inside of your User model:
class User < ActiveRecord::Base
belongs_to :country
delegate :image_url, :to => :country, :prefix => true, :allow_nil => true
end
Now your helper becomes simply:
def image(user)
if user.country_image_url
image_tag "flags/#{user.country_image_url}.png"
end
end
Law of Demeter states:
Each unit should have only limited knowledge about other units: only units "closely" related to the current unit.
Also check out Rail Best Practices Law of Demeter; if nothing else you're saving yourself the extra clause in your if statement & your code looks pretty.

rails custom validation on action

I would like to know if there's a way to use rails validations on a custom action.
For example I would like do something like this:
validates_presence_of :description, :on => :publish, :message => "can't be blank"
I do basic validations create and save, but there are a great many things I don't want to require up front. Ie, they should be able to save a barebones record without validating all the fields, however I have a custom "publish" action and state in my controller and model that when used should validate to make sure the record is 100%
The above example didn't work, any ideas?
UPDATE:
My state machine looks like this:
include ActiveRecord::Transitions
state_machine do
state :draft
state :active
state :offline
event :publish do
transitions :to => :active, :from => :draft, :on_transition => :do_submit_to_user, :guard => :validates_a_lot?
end
end
I found that I can add guards, but still I'd like to be able to use rails validations instead of doing it all on a custom method.
That looks more like business logic rather than model validation to me. I was in a project a few years ago in which we had to publish articles, and lots of the business rules were enforced just at that moment.
I would suggest you to do something like Model.publish() and that method should enforce all the business rules in order for the item to be published.
One option is to run a custom validation method, but you might need to add some fields to your model. Here's an example - I'll assume that you Model is called article
Class Article < ActiveRecord::Base
validate :ready_to_publish
def publish
self.published = true
//and anything else you need to do in order to mark an article as published
end
private
def ready_to_publish
if( published? )
//checks that all fields are set
errors.add(:description, "enter a description") if self.description.blank?
end
end
end
In this example, the client code should call an_article.publish and when article.save is invoked it will do the rest automatically. The other big benefit of this approach is that your model will always be consistent, rather than depending on which action was invoked.
If your 'publish' action sets some kind of status field to 'published' then you could do:
validates_presence_of :description, :if => Proc.new { |a| a.state == 'published' }
or, if each state has its own method
validates_presence_of :description, :if => Proc.new { |a| a.published? }

Ruby on Rails Validation Question Inside Controller

Let's say I have a form_tag in a view gathering a view user input . With this input that I get through the params hash, I want to verify some of htis information such as email phone name.
Can I just verify in the controller or is this a bad thing? I don't plan to save the thing I get to a db or anything, it's just getting put into an email and sent off, but I want to verify these things before it's sent.
Thank you.
EDIT:
Found this http://www.viddler.com/explore/rails3/videos/6/
class Test
include ActiveRecord::Validations
validates_presence_of :name, :email
attr_accessor :name, :email
end
You can use the model for whatever you need that is related to the object and don't need to save it. Keeping stuff like this in the model is desirable in order to keep controller tidy. Say you have a user model:
#controller
#user.new params[:user]
#user.check_valid
#user.save # is optional
#user.rb
def check_valid
!email.blank? and !phone.blank?
end

How do I handle nils in views?

I have the following models set up:
class Contact < ActiveRecord::Base
belongs_to :band
belongs_to :mode
validates_presence_of :call, :mode
validates_associated :mode, :band
validates_presence_of :band, :if => :no_freq?
validates_presence_of :freq, :if => :no_band?
protected
def no_freq?
freq.nil?
end
def no_band?
band.nil?
end
end
class Band < ActiveRecord::Base
has_many :logs
end
class Mode < ActiveRecord::Base
has_many :logs
end
When I enter a frequency on my new view it allows for no band to be specified if a freq is entered. This creates a problem in my other views though because band is now nil. How do I allow for band not to be specified and just show up as empty on my index and show views, and then in the edit view allow one to be specified at a later point in time.
I have been able to get my index to display a blank by doing:
contact.band && contact.band.name
But I'm not sure if this is a best approach, and I'm unsure of how to apply a similar solution to my other views.
Many thanks from a rails newb!
In my views, I use the following for potentially nil objects in my views:
<%= #contact.band.name unless #contact.band.blank? %>
if your object is an array or hash, you can use the empty? function instead.
<%= unless #contacts.empty? %>
..some code
<% end %>
Hope this helps!
D
A couple years old but still a top Google result for "rails view handle nil" so I'll add my suggestion for use with Rails 3.2.3 and Ruby 1.9.3p0.
In application_helper.rb, add this:
def blank_to_nbsp(value)
value.blank? ? " ".html_safe : value
end
Then to display a value in a view, write something like this:
<%= blank_to_nbsp contact.band %>
Benefits:
"blank" catches both nil values and empty strings (details).
Simply omitting a nil object, or using an empty string, may cause formatting issues. pushes a non-breaking space into the web page and preserves formatting.
With the "if" and "unless" suggestions in other answers, you have to type each object name twice. By using a helper, you only have to type each object name once.
<%= #contact.try(:band).try(:name) %>
This will return nil if band or name do not exist as methods on their respective objects.
You can use Object#andand for this:
<%= #contact.band.andand.name %>
<%= #contact.band if #contact.band %> also works

Rails form validation conditional bypass

I have a rails model that validates uniqueness of 2 form values. If these 2 values aren't unique the validation errors are shows and the "submit" button is changed to "resubmit". I want to allow a user to click the "resubmit" button and bypass the model validation. I want to do something like this from the rails validation documentation:
validates_uniqueness_of :value, :unless => Proc.new { |user| user.signup_step <= 2 }
but I don't have a a value in my model that I can check for...just the params that have the "Resubmit" value.
Any ideas on how to do this?
In my opinion this is the best way to do it:
class FooBar < ActiveRecord::Base
validates_uniqueness_of :foo, :bar, :unless => :force_submit
attr_accessor :force_submit
end
then in your view, make sure you name the submit tag like
<%= submit_tag 'Resubmit', :name => 'foo_bar[force_submit]' %>
this way, all the logic is in the model, controller code will stay the same.
Try this:
Rails 2: Model.save(false)
Rails 3: Model.save(:validate => false)
It bypasses validations (all of them though).
Not positive about this, but you could try to add an attr_accessor to your model to hold whether or not the form has been submited once before.
just add
attr_accessor :submitted
to your model and check for it in your validations.
You can just look at the submit button to determine whether you want to perform the validations.
def form_method
case params[:submit]
when "Submit"
'Do your validation here'
when "Resubmit"
'Do not call validation routine'
end
end

Resources