First and foremost, thanks for taking time to read and respond to my questions. I really appreciate it.
I'm not looking for the exact code on how to achieve the following but more of a direction or path I should follow.
Users that are logged in can create different courses. I've added a requirement (a provider) for each course and I want the user to have at least one provider associated (using rolify for this) to them before doing so but I'd like this to be on the same view (courses#new)
I've tried the following:
Nested forms (Doesn't work since I require at least one provider upon course creation)
Adding the providers#new in a modal on the page (can't call a controller from another one using form_form(#provier)
I've thought of the following:
Redirect the users to providers#new if they haven't created one first
Add a modal with a form_tag element that creates a provider and then refreshes the underlying page.
What are your thoughts? Better ideas?
Thanks!
Francis
My courses#new (_form) view
<%= simple_form_for(#course) do |f| %>
<%= f.error_notification %>
<%= f.input :name %>
<%= f.input :description, as: :text, input_html: { rows: '2' } %>
<%= f.association :provider, :value_method => :id, collection: Provider.with_role(:provider_admin, current_user), input_html: { class: 'input-large' }, include_blank: false %>
<div class="form-actions">
<%= f.button :submit, :class => 'btn-primary' %>
<%= link_to "Cancel", :back, class: 'btn' %>
</div>
<% end %>
models/provider.rb
class Provider < ActiveRecord::Base
attr_accessible :description, :name
validates :name, :presence => true
validates :description, :presence => true
validates :name, :length => { :minimum => 6, :maximum => 100 }
validates :description, :length => { :minimum => 6, :maximum => 100 }
has_many :courses
end
models/course.rb
class Course < ActiveRecord::Base
attr_accessible :description, :name, :provider_id
validates :name, :presence => true
validates :name, :length => { :minimum => 6, :maximum => 100 }
validates :description, :presence => true
validates :description, :length => { :minimum => 6, :maximum => 256 }
validates :provider_id, :presence => true
belongs_to :provider
has_many :sessions, :dependent => :destroy
end
I like the idea where you do a redirect in courses#new to providers#new when !current_user.provider.any?.
But I would probably go the nested forms way. You can use one form to create a new course and a new provider if a user doesn't have a provider. Have a look at http://railscasts.com/episodes/196-nested-model-form-revised to get a quick idea. I think that this would be best UI wise.
Related
I am trying to make this input in my search required to start a search. I tried :validate if there is input but that didn't work. Any suggestions?
<%= text_field_tag "location", params[:location], :placeholder => 'City, zipcode, or address' %>
change the syntax
<%= text_field_tag "location", "#{params[:location]}", :placeholder => 'City, zipcode, or address' {:required => true} %>
and add this to your model
validates :location, presence: true
In whatever model the location belongs to, try adding this syntax:
class whatever < ActiveRecord::Base
validates :location, presence: true
end
make sure that location is part of attar_accessible in your model.
I have a form where the user is prompt to enter a title and either :this or :that. A user can't enter both fields.
<% f.input :title%>
<% f.input :this %>
<% f.input :that%>
for my :title i have in my Model
validates :title, :presence => true
How can i pass a validation for either :this or :that
You can do this
validates :that, :presence => true, :if => Proc.new {this.blank?}
validates :this, :presence => true, :if => Proc.new {that.blank?}
Wouldn't just the first line be sufficient?
validates :that, :presence => true, :if => Proc.new {this.blank?}
If 'this' is blank and so is 'that', the first line would fail validation, so you wouldn't need the second line.
I'm workin on ROR app using Rails 3.2.9 and I'm getting the error messages for a sign up page in my app as follows
<li>Login is too short (minimum is 3 characters)</li><li>Email is too short (minimum is 7 characters)</li><li>Email is invalid</li><li>Password can't be blank</li><li>Password is too short (minimum is 4 characters)</li><li>Password is invalid</li><li>Password confirmation can't be blank</li>
These are the default messages of Active Record Validation . (ref: http://guides.rubyonrails.org/active_record_validations_callbacks.html )
This app was previously written in Rails 2 and later migrated to rails 3. I have changed the validates_presence_of commands to validates : password , :presence=>true etc in accordance with rails 3 .
In the view ( signup.html.erb) error_messages_for is rendering these msgs. It is deprecated from rails 3.
Can anyone tell me what needs to be used instead of error_messages_for in the view and all code needs to be changed correspondingly for getting the error msgs right..
Here's the code (not complete)
user.rb in app/model
class User < ActiveRecord::Base
has_many :excel_files # One user may have many excel files
has_one :user_access_validity# One user may have one license period
# Virtual attribute for the unencrypted password
attr_accessor :password
attr_accessible :login
attr_accessible :email
attr_accessible :password
attr_accessible :password_confirmation
attr_accessible :company
#changes of 'validates' in accordance with rails 3:
validates :login, :presence => true,
:length => { :within => 3..40},
:uniqueness => { :case_sensitive => false },
:format => { :with => /^([a-z_0-9\.]+)$/i },
:on => :create,
:if => :is_login_entered?
validates :email, :presence => true,
:length => { :within => 7..100},
:uniqueness => { :case_sensitive => false },
:format => {:with => /^([a-z]+((\.?)|(_?))[a-z0-9]+#(mindtree.com|rvce.edu.in))$/i},
:on => :create,
:if => :is_email_entered?
validates :company, :presence => true,
:format => { :with =>/(mindtree|RVCE)/i},
:format => { :with => /^([a-z]+)$/i },
:on => :create,
:if => :is_company_entered?
#validates_presence_of :login, :email, :company
on => :create, :if => :is_login_entered?
validates :password, :presence => true,
:length => { :within => 4..40 },
:confirmation => true,
:format => { :with => /^([a-z0-9#!#\$]+)$/i },
:on => :create,
:if => :password_required?
validates :password_confirmation, :presence => { :if => :password_required? }
#validates_presence_of :password_confirmation, :if => :password_required?
before_save :encrypt_password
.
.
.
In signup.html.erb
<font color=red>(Fields marked * are mandatory)</font><h3>Sign me up!</h3>
<br>
<span class='error'><%= error_messages_for (#user) %></span>
<%= form_for :user do |f| -%>
<p><label for="login"><span class='redcolor'>*</span>Login</label><br/>
<%= f.text_field :login %></p>
<p><label for="email"><span class='redcolor'>*</span>Email</label><br/>
<%= f.text_field :email %></p>
<p><label for="password"><span class='redcolor'>*</span>Password</label><br/>
<%= f.password_field :password %></p>
<p><label for="password_confirmation"><span class='redcolor'>*</span>Confirm Password</label><br/>
<%= f.password_field :password_confirmation %></p>
<p><label for="company"><span class='redcolor'>*</span>Company</label><br/>
<%= f.text_field :company %></p>
<p><%= submit_tag 'Sign up' %></p>
<% end -%>
Solution
Got the following code from http://www.rubydoc.info/github/edavis10/redmine/ApplicationHelper:error_messages_for which shud be added in application_helper.rb and corresponding change in html.erb file as <%= error_messages_for (#user) %>
Code:
def error_messages_for(*objects)
html = ""
objects = objects.map {|o| o.is_a?(String) ? instance_variable_get("##{o}") : o}.compact
errors = objects.map {|o| o.errors.full_messages}.flatten
if errors.any?
html << "<div id='errorExplanation'><ul>\n"
errors.each do |error|
html << "<li>#{h error}</li>\n"
end
html << "</ul></div>\n"
end
html.html_safe
end
http://guides.rubyonrails.org/active_record_validations_callbacks.html
if you read this guide you will see that in you form you can use form.error_messages
Solution for the question is added below the question
I am kinda new to Rails and this is my first post to StackOverflow.
Say I have 3 models:
class Product < ActiveRecord::Base
default_scope :order => :title
has_many :line_items
has_many :promo_products
has_many :promotions, :through => :promo_products, :foreign_key => :promotion_id
before_destroy :ensure_not_referenced_by_any_line_item
before_destroy :ensure_not_referenced_by_any_promo_product
validates :title, :presence => true, :uniqueness => true
validates :description, :presence => true
validates :price, :numericality => {:greater_than_or_equal_to => 0.01}
private
def ensure_not_referenced_by_any_line_item
if line_items.empty?
return true
else
errors.add(:base, 'Line Items present')
return false
end
end
def ensure_not_referenced_by_any_promo_product
if promo_products.empty?
return true
else
errors.add(:base, 'Some promotions are still in effect')
return false
end
end
end
class Promotion < ActiveRecord::Base
CART_OR_PRODUCT = ['Cart', 'Product']
PROMOTION_TYPE = ['Percentage based', 'Value based']
has_many :promo_products
accepts_nested_attributes_for :promo_products
has_many :products, :through => :promo_products, :foreign_key => :product_id
accepts_nested_attributes_for :products
#attr_accessible :promo_products_attributes, :title, :description, :cart_or_product, :promotion_type, :discount, :minimum_price, :minimum_quantity
validates :title, :description, :presence => true
validates :cart_or_product, :inclusion => {:in => CART_OR_PRODUCT, :message =>
"is invlaid. Please select a valid option"}
validates :promotion_type, :inclusion => {:in => PROMOTION_TYPE, :message =>
"is invalid. Please select a valid option"}
validates :discount, :minimum_price, :numericality => {:greater_than_or_equal_to => 0.00}
validates :minimum_quantity, :numericality => {:greater_than_or_equal_to => 0}
end
class PromoProduct < ActiveRecord::Base
belongs_to :promotion
belongs_to :product
accepts_nested_attributes_for :products
end
In the promotions new page, I would like to show list of products that could be part of a promotion. A user may select 0, 1 or more products, depending on the type of promotion.
In the action new of promotions_controller, I built like this:
#promotion.promo_products.build.build_product
In the _form of promotions, I needed to show the list of products for user to select. I made a nested form like:
<%= form_for(#promotion) do |f| %>
<!-- other promotion fields -->
<%= f.fields_for :promo_products do |pp| %>
<%= pp.fields_for :products do |p| %>
<div class="field">
<%= f.label "Products" %><br />
<%= collection_select :promo_product, :product_id, Product.all, :id, :title {:selected => #promotion.product_ids}, {:multiple => true} %>
</div>
<% end %>
<% end %>
<% end %>
I have 2 issues.
First my code throws an error:
ArgumentError in PromotionsController#new
No association found for name `products'. Has it been defined yet?
If I change the line in PromoProduct model:
accepts_nested_attributes_for :products
to
accepts_nested_attributes_for :product
Then there are no errors, and everything works fine.
The data doesn't get saved to promo_product table. I have the create action in promo_product controller as:
def create
#promotion = current_promotion
products = Product.select(:id => params[:product_id])
products.each do |p|
promo_product = #promotion.promo_products.build(p)
promo_product.save
end
##promo_product = PromoProduct.new(params[:promo_product])
redirect_to promotions_path
end
How can I go about it?
Thank you.
You shouldn't put the "accept_nested_attribute_for" in the association table PromoProducts. It should exist in the model that you want to use for creating association to another model. "accept_nested_attribute_for" IIRC simply inserts an "[association]_attributes=" method for your model. For instance, if you add this method to your Product class for Promotion, you will get "promotion_attributes=" method inserted in the Product class. Then a nested form can use this function to create new objects with a hash that represents the model and association.
Base on the above, the create action shouldn't be in PromoProduct controller, instead it should be in Promotion controller.
<%= form_for(#promotion) do |f| %>
<!-- other promotion fields -->
<%= f.fields_for :products do |pp| %>
<div class="field">
<%= f.label "Products" %><br />
<%= collection_select :promo_product, :product_id, Product.all, :id, :title {:selected => #promotion.product_ids}, {:multiple => true} %>
</div>
<% end %>
<% end %>
I don't know without trying if the above collection_select line is correct. But you can debug this by checking the parameter returned by the form to the controller in the server console log. Basically you should see a nested hash of
{:promotion => {:products => ...}}
Let me know if you need more help on this. In my solution I used a combination of select_tag and options_from_collection_for_select. (But I don't recall the behavior of all these offhand without looking at the API doc.)
Lastly, do you need the :through model? I think since you created the through model you need to handle saving that in your create action. But since you don't have other attributes on the PromoProducts table I wonder if you want to simply leave it as a HABTM association and let rails deal with the rest?
I'm trying to validate the value of a form (a checkbox actually) in a model, but am having a lot of trouble finding what to pass validates:
validates :agreement, :agreement => true
I've gotten other things to work like:
validates :password, :presence => true, :length => {:minimum => 6, :maximum => 25}, :confirmation => true
My view looks like this:
<% form_for :signup_form, :url => {:controller => "user", :action => "post_signup"} do |f| %>
...
<%= f.check_box( :agreement ) %> I agree to the <%= link_to("Terms of Service", :controller=> "about", :action => "terms") %> and <%= link_to("Privacy Policy", :controller=> "about", :action => "privacy") %>
...
Which then goes to my controller:
agreement = params[:signup_form][:agreement]
new_user = User.create(:login_name => login_name, :first_name => first_name, :last_name => last_name, :email => email, :password => password, :agreement => agreement, :created_at => DateTime.now())
And then my model.
Thanks for any help you can offer in advance.
You might be looking for :acceptance => true or validates_acceptance_of
You'll want to display your errors on the page, and ensure your validation is working at all. I would re-implement your validation as:
# app/models/user.rb
class User < ActiveRecord::Base
validates :agreement do |ag|
ag.errors.add "Must agree to the terms" unless self.agreement
end
end
see http://asciicasts.com/episodes/211-validations-in-rails-3 for a comprehensive treatment, including a nice way to display the errors.