Error messages from model in Rails 3.2 - ruby-on-rails-3

Currently my app includes the following code to display the error messages on a view from model.rb but it is not updated code as error_messages_for is deprecated in Rails 3. Can anyone please suggest me how to do the same in Rails 3?? I want the logic to be in model.rb file and from there I should be able to display error msgs on view
excel_file.rb(model.rb)
#jus some sample function
def show_error(test_file)
if test_file == 'Upload Test Case'
errors[:base] << "Please upload excel sheet with testsuite config sheet and testcases"
elsif test_file == 'Upload Test Data'
errors[:base] << "Please upload excel sheet with test data"
end
end
sampleview.html.erb
#some code..
<span class='error'><%= error_messages_for (#excel_file) %></span>
#some code..
application_helper.rb
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

You could use https://github.com/rails/dynamic_form.
It provides the functionality you want.
Update
You are right, this is not in accordance to Rails 3.
You should probably do something like this:
Create a shared partial
/app/views/shared/_error_messages.html.erb
<% if target.errors.any? %>
<div id="errorExplanation">
<h2><%= pluralize(target.errors.count, "error") %> prohibited this record from being saved:</h2>
<ul>
<% target.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
And call it like this:
<%= render "shared/error_messages", :target => #excel_file %>
So why are the methods error_messages_for and f.error_messages removed? Ryan bates says the following:
The reason that the methods have been removed is that the display of the error messages often needs to be customized and doing this through the old methods was a little bit cumbersome and not as flexible as having the error message HTML inline as we have now. Having the HTML to hand in the views means that we can change the display of the error messages however we like.
source: http://asciicasts.com/episodes/211-validations-in-rails-3
Update 2
This works for custom validations the same way
validate :show_error
def show_error
if test_file == 'Upload Test Case'
errors[:base] << "Please upload excel sheet with testsuite config sheet and testcases"
elsif test_file == 'Upload Test Data'
errors[:base] << "Please upload excel sheet with test data"
end
end

Solution:
Create a shared partial
app/views/common/_error_messages.html.erb:
<% if target.errors.any? %>
<div id="errorExplanation">
<h2><%= pluralize(target.errors.count, "error") %> prohibited this record from being saved:</h2>
<ul>
<% target.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
And call it like this:(in sampleview.html.erb)
<% if #excel_file %>
<%= render "common/error_messages", :target => #excel_file %>
<% end %>
Put up the if condition to avoid the error NoMethodError:Undefined method 'errors' in target.errors.any?. This avoids the page from throwing this error and renders the partial view only when an instance of target(#excel_file) is present.
This works for custom validations the same way
In excel_file.rb(model.erb) in app/model:
def show_error
if test_file == 'Upload Test Case'
errors[:base] << "Please upload excel sheet with testsuite config sheet and testcases"
elsif test_file == 'Upload Test Data'
errors[:base] << "Please upload excel sheet with test data"
end
end
This worked perfectly! Now I'm able to get the error notifications properly :)

Related

Reference several Class objects with one line of code (Rails)

I have this code in the (ERB) view file:
<% if current_page?(some_object_path(some_object)) %>
<%= f.submit "Create Some Object", class:'btn btn-success'%>
<% else %>
<%= f.submit "Update Some Object", class:'btn btn-info'%>
<% end %>
and this:
<%= form_tag import_some_object_path, multipart: true do %>
<%= file_field_tag :file, class: "" %>
<%= submit_tag "Import CSV", class: "btn btn-info " %>
<% end %>
Now, the issue is that I have several of these different paths relating to respective classes (tables in the database). I don't want to replicate these codes in all 9 Class views in the app. Is there a way to refactor this so I can reference the code in just one location (say, a _partial), and then rails knows what object to insert in the some_object field depending on say, the current_page? Is there a magic wand way to do this?
(I have really scoured the internet but I can't find a solution. It may be that I am using the wrong search terms though)

Finding Active Record Associations in Rails Using SQL

New to Rails and SQL and I'm trying to access associations in my app.
I have an itinerary web app where users can come and download itineraries. As part of the process they can leave reviews with their thoughts. I want the owner of the review to be able to edit or delete her review after the thought if need be, but the following Active Record Association is returning an error for #itinerary.reviews.user_id:
undefined method `user_id' for #<Review::ActiveRecord_Associations_CollectionProxy:0x007fb969392978>
Inside my itineraries_helper:
def user_is_reviewer?
#itinerary = Itinerary.find(params[:id])
!!current_user.id == #itinerary.reviews.user_id
end
In my view:
<div class = "review-container">
<h2>What Travelers Thought</h2>
<% if #itinerary.reviews.count > 0 %>
<% #itinerary.reviews.each do |review| %>
<div class = "reviews">
<div class = "star-rating" data-score= <%= review.rating %> ></div>
<p>
<%= review.comment %>
</p>
<% if user_is_reviewer? %>
<% link_to "Edit", edit_itinerary_review_path(#itinerary, #review) %>
<% end %>
<% end %>
</div>
Questions:
Why does Review.first.user_id work but not itineraries.reviews.user_id
What SQL command will achieve what I am looking for?
If I can use SQL, what SQL resource can I pick up to learn more? If not, whats a better way?
Review.first will return your a Review Object and you are accessing the user_id associated with it by Review.first.user_id
while
itinerary.reviews
is returning a collection of all the reviews that belongs to a particular itinerary and it is collection of active record objects and you were trying to access the user_id from active record collection which is not going to work.
You can solve it by passing review id to your helper method
def user_is_reviewer?(review_id)
review = Review.find(review_id)
!!current_user.id == review.user_id
end
In your view updating the helper method to have review id passed
<% if user_is_reviewer?(review) %>
<% link_to "Edit", edit_itinerary_review_path(#itinerary, #review) %>
<% end %>
OR else you can simply go without a helper method as you already have a review object like following in your view
<% if current_user.id == review.user_id %>
<% link_to "Edit", edit_itinerary_review_path(#itinerary, #review) %>
<% end %>

flash_timedout = "true" when user session expires in rails using devise

My code for session time out is as follows:
In sessions_controller:
prepend_before_filter { request.env["devise.skip_timeout"] = true }
In user model:
devise :timeoutable, :timeout_in => 2.minutes
application.html.erb:
<%=content_tag :div, msg, :class =>"flash_#{key}", :id => "app_flash"%>
If my session expires, i am getting an error "Your session has expired..." from devise errors which is fine.
But i am getting extra error outside the form as "true" where i inspect it as [:flash_timedout].
Please help me how to disable this true [:flash_timedout] ?
That is a known issue. You must only display :notice and :alert messages or remove the :timedout key from the flash hash as stated in the Devise documentation.
See https://github.com/plataformatec/devise#configuring-controllers
I was able to disable [:flash_timedout] "true" and provide customized error.
I wrote below steps in my message partial:
<% if flash[:timedout] && flash[:alert] %>
<% flash.keep(:timedout) %>
<% flash.keep(:alert) %>
<div class = "alert alert-danger">
Your session expired. Please sign in again to continue.
</div>
<% else %>
<% flash.each do |name, message| %>
<div class = "alert alert-<%= message.include?('Invalid') ? 'danger' : 'success'%>">
<ul>
<%= message %>
</ul>
</div>
<% end %>
<% end %>

Simple_Form and Bootstrap 3 Form Validation Notification Stopped Working

I'm still learning RoR and have followed various tutorials online. In that process I believe I have messed up the nice flash notifications that Bootstrap 2 showed when validating Simple_Form submissions. I have tried to update my code, but without success. Here is what I have so far...
Running:
Rails 3.2.13
Ruby 2.0.0
I just upgraded to Bootstrap 3 using this gem in my gemfile:
gem 'bootstrap-sass-rails'
In my application.html.erb I have:
<%= render 'layouts/messages' %>
In my _messages partial I have:
<% flash.each do |type, message| %>
<div class="alert <%= bootstrap_class_for(type) %> fade in">
<button class="close" data-dismiss="alert">×</button>
<%= message %>
</div>
<% end %>
In my application_helper.rb I have:
def bootstrap_class_for flash_type
case flash_type
when :success
"alert-success"
when :error
"alert-error"
when :alert
"alert-block"
when :notice
"alert-info"
else
flash_type.to_s
end
end
In my users_controller.rb I have:
def update
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'Account successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
And in my edit.html.erb view I have:
<%= simple_form_for(#user) do |f| %>
<%= f.input :firstname %>
<%= f.input :lastname %>
<%= f.input :email %>
<%= f.input :password %>
<%= f.input :password_confirmation %>
<%= f.submit "Save changes", class: "btn btn-lg btn-primary" %>
<% end %>
The validation works, but when returned to the edit view, no formatting (red for errors) or flash message appears. Only a very hard to spot message outside each field is displayed. I must be missing some link between Simple_Form and Bootstrap 3, just don't know what.
I found another post where poster suggested to add:
config.input_class = "form-control"
to my simple_form initializer, but that gave me an error (think I might not have the latest version?):
undefined method `input_class=' for SimpleForm:Module (NoMethodError)
I wish I knew what was going on but I really hope someone can help me get the formatting and flash messages back. Apologies if this is a total newbie question, but I feel a little lost and possibly regretting that I upgraded too soon to Bootstrap 3 maybe.
A thousand thanks in advance to anyone reading all this :)
I got the following mix of code from railscasts.com and other websites.
<% flash.each do |name, msg| %>
<div class="alert alert-<%= name == :notice ? "success" : "error" %>">
<a class="close" data-dismiss="alert">×</a>
<%= msg %>
</div>
<% end %>
Add this to the top of your controller:
respond_to :html, :json
Put this in each controller action:
def create
...
flash[:notice] = 'User was successfully created.'
respond_with(#user)
end
works with rails 3.2+ and 4.0 and twitter bootstrap rails 2, untested in tbsr 3 but will probably work fine.
This worked for me far much better than others as it;s shorter and includes all alert cases -> error, success, alert & notice provided by Bootstrap.
N.B: I renamed your _messages partial to _flash_messages because that is what most people use.
And for those who may be wondering where to generate the _flash_messages partial, it's pretty easy, just right-click your layouts folder in views and 'add new file'. You can call it _flash_messages as I've done, and ensure you have that first underscore (_) before 'flash...'. Tap 'Save'
Now in your _flash_messages.html.erb partial, use this
<% unless flash.blank? %>
<% flash.each do |type, message| %>
<div class="alert <%= flash_class(type.to_s) %>">
<button class="close" data-dismiss="alert">x</button>
<%= message %>
</div>
<% end %>
<% end %>
And in your application_helper.rb use this
def flash_class (type)
case type
when 'error'
"alert-error"
when 'notice'
"alert-info"
when 'alert'
"alert-block"
when 'success'
"alert-success
else
type.to_s
end
end
Then in your application.html.erb, add this as your first line in your first div
<%= render partial: 'layouts/flash_messages', flash: flash %>
Notice that we render the partial (any partial that is), without the 'starter' underscore(_), i.e before the word 'flash..'
You can check out this answer from teamtreehouse on displaying different alert cases.
Hope this helps!

Rails: Two separate create forms..how to keep them separate?

In Rails 3.0 I have the standard 'new' form that creates a new record, in this case a patient. It works fine and the validations / error showing also work fine.
The client now wants the form in Spanish.
So, I did this:
Created a new html doc called "newspanish" (Cut / paste code from "patients/new")
Created a new partial called "_form_newspanish" and referenced it where the "form" partial is in "newspanish" (Cut / paste code from view "patients/_form")
Created a controller action in "patients" called "newspanish" and cut/pasted exact code from the "new" action.
I left the "create" action untouched.
Added match "patients/newspanish" to routes.
Translated the english parts to spanish in views/newspanish and views/_form_newspanish. Just the stuff that users read on the page, of course...not the rails code.
And, it works, for perfect submissions.
For submissions that fail validation (like putting 3 digits in as a phone number), the page reverts to the view "patients/new" and shows the errors above the form... in English, of course, because patients/new is in English.
Of course, I want it to revert to "views/newspanish" and also show custom verbage in the validations errors (spanish).
Any thoughts on how I can get the patients/newspanish view to load when error validation it tripped?
Here's my code for "_form_newspanish"
<%= form_for(#patient) do |f| %>
<% if #patient.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#patient.errors.count, "error") %> prohibited this subscriber from being saved:</h2>
<ul>
<% #patient.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p><label for="mobile">Número de teléfono celular o móvil*</label>: <%= f.text_field :mobile %></p>
<br />
<%= f.submit "Inscribirme" %>
</div>
<% end %>
And controller... patients/newspanish
def newspanish
#patient = Patient.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #patient }
end
end
<%= form_for(#patient) do |f| %>
is creating a form whose url is submits to is "/patients" which matches to patients_controller, create action.
That create action probably has a line that says (in my pseudo code)
if #patient.save
redirect to somewhere
else
render :new
end
That line "render :new" is showing the "patients/new" view.
So what you have to figure out is to either
1) detect in patients_controller # create how to tell if its spanish, and render "newspanish"
OR
2) change <%= form_for(#patient) do |f| %> to submit to a new url that just handles the spanish version, and make a new controller or action that just handles the spanish form (and renders "newspanish" if the #patient doesn't save
For #2, you could manually change where the form submits to with
<%= form_for(#patient), :url => spanish_patients_path do |f| %>
and in your routes create
post "patients/spanish" => "patients#create_in_spanish"
and add def create_in_spanish to your patients controller