IF conditional inside a nested Has_one - ruby-on-rails-3

psuedo relational run down
Clients -> has_many -> Departments -> has_many -> Tasks -> has_one -> Hazard
On the Tasks#show I currently the hazard only if it exists (as determined by a Yes/no question in the Task form). If it exists I would like to show the Hazard with a conditional statement that shows the "fill out form" link and "Incomplete" text if the Hazard form has not been completed. and a "view form" and "complete text if the Hazard form has been completed.
here is an excerpt of code from the app/views/tasks/show.html.erb
<% if #task.Hazard_exist == 'Yes' %>
<tr>
<td>Hazard</td>
<% if #task.Hazard.nil? %>
<td><%= link_to 'Fill Out Form', new_client_department_task_Access_path(#client,#department,#task) %></td>
<td id="incomplete">Incomplete!</td>
<td class="risk_val">Form not complete</td>
<% else %>
<td><%= link_to 'View Form', client_department_task_Hazard_path(#client,#department,#task) %>
<%= link_to 'Edit Form', edit_client_department_task_Hazard_path(#client,#department,#task) %></td>
<td id="complete">Complete</td>
<td class="risk_val"><%= #task.Hazard.risk_total%></td>
<% end %>
</tr>
<% end %>
This works but the issue is that even if I "fill out the form" and then hit cancel the row of the database #task.Hazard is no longer nil. Thus identifying the Hazard form as "Complete". Ideally I'd like to make it so that the Hazard is validated by presence of certain fields but the client wants it to be able to be submitted as "in progress" So My plan is that the form will be able to be submitted with no validations. However, the conditional statement in the Tasks#show would be dependent on a key value in the Hazard model not being blank.
i.e. replacing this line
<% if #task.Hazard.nil? %>
with
<% if #task.Hazard.risk_total == '' %>
However, I get the "undefined" method issue when trying to do this.
Is there any easy work around here in order to use this conditional requirement? Or is simply putting a validation on the form the best way?

If the client wants this to be able to be submitted in progress then you're not going to get where you want to go just checking for existence. Instead, add a complete:boolean attribute on your models that need to be submitted in progress, then either allow these to be set by the user or in a callback.
For instance, a good way to do this might be to provide two buttons at the bottom of the form:
= submit_tag "Save as Draft"
= button_tag "Save as Complete", :type => "button", :id => "complete"
You can then call a script that takes the click event on button#complete, adds a hidden field complete = true, and submits the form.
That script might look like:
$('button#complete').click( function(event) {
event.preventDefault();
$('form#my_form').append('<input type="hidden" name="hazard[complete]" value="true">').submit();
});
Or, you could put a callback in the model that checks for whether all the fields on the hazard have been filled out to, and then marks it as complete.
Then in your conditional you just would write:
if #task.hazard.complete

Related

Rails dropdown/select location objects with individual params

My scenario is on the home page I want to click a dropdown toggle/select. In that toggle I want it to display a list of Location objects. However I want to pass individual params that are different in each one. My goal is to use a dropdown to toggle location information in the view. The problem is right now I'm hard coding locations into this drop down. But I am creating Location objects on a different page. I want those Location objects to populate the dropdown on the home page, but allow the user's choice to pass params to change the view. This would allow an unlimited number of locations. What is a good way to accomplish this.
index.html.erb
**I erased the dropdown code to simplify things.**
<li><%= link_to "#{#location1}", {:location1 => "location1"}%></li>
<li><%= link_to "#{#location2}", {:location2=> "location2"}%></li>
home_controller.rb
if params[:location1]
#current_location = Location.last
#myreviews = Review.where("location_id = ?", #current_location.id).order('created_at asc')
end
if params[:location2]
#current_location = Location.first
#myreviews = Review.where("location_id = ?", #current_location.id).order('created_at asc')
end
SOLUTION
Here is what I did to solve the problem in the end.
View
<ul class="dropdown-menu loc-drop scrollable-menu" role="menu" aria-labelledby="menu1">
<% #locations.each do |u| %>
<li><%= link_to u.name, :params => {:loc => u.id} %></li>
<% end %>
</ul>
</ul>
Controller
#locations = Location.all
if params[:loc]
#chosen_location = Location.where('id = ?', params[:loc]).pluck(:id).first
end
At that point I'm using #chosen_location to display details like name and address.

Why is my instance not saving for my search form?

I've got a search form that returns our products. However, if a user inputs a string that contains certain words (in this instance, 'color'), it returns far too many products. I'm trying to remove the string 'color' from the query that is searched on the backend, but maintain the original query's string as #unfiltered_query so I can reference the #unfiltered_query on the front-end template.
if query.include? "color"
#unfiltered_query = query
end
query.slice! "color"
values = query.split
binding.pry
It was not working, so I ran pry to see what was going on. In the form, I searched "Red paint color". When I call #unfiltered_query in pry, it outputs "Red paint", even though I create the method before .slice! is called?!
What am I missing?
Thank you!
p.s. the HTML template that I'm using to reference the instance is:
<div class="search-input"><h2>
<% if #unfiltered_query.present? %>
<%= #unfiltered_query.titleize %>
<% else %>
<%= query.titlelize %>
<% end %>
</h2></div>
Can you try like this :
if query.include? "color"
#unfiltered_query = query.dup
end
query.slice! "color"
values = query.split
binding.pry
This could be due to passing by reference.

Display only one field from an embedded document with MongoID

I'm a real beginner with MongoDB and MongoID.
I created two scaffolds
class Objet
include Mongoid::Document
field :nom, type: String
embeds_one :coordonnee
end
And
class Coordonnee
include Mongoid::Document
field :adresse1, type: String
field :adresse2, type: String
field :code_postal, type: String
field :ville, type: String
embedded_in :objet
end
That's what I get when creating a new Objet :
Now, I'm trying to show only the field adresse1 for this document, but it doesn't work. I can display only the whole embedded document doing this :
When I do :
<%= #objet.coordonnees.adresse1 %>
I get this error :
undefined method `adresse1' for #<Hash:0x2b2b1f0>
How can I do that ?
EDIT
Doing that, I can display all the elements "Adresse1, adresse2, ville, code_postal" :
Controller
def show
#objet = Objet.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #objet }
end
end
View
<%= #objet.nom %>
<% #objet.coordonnee.each do |t| %>
<%= t[1] %>
<% end %>
But my question is : How to display ONLY one of them ? Such as ville, or code_postal or adresse1... ?
What was your code that works for the full document? It was dropped from your post.
In the mongo Shell, you could do this with dot notation db.collection.find({},{'coordonnees.adresse1':1,'_id':0}) You need to specify the '_id':0 because _id is always returned by default.
The other answer will not work because adresse1 is a subdocument. You must include the reference to coordonnees.
Not hugely familiar with MongoID, but assuming you can make calls straight to mongo, there is a second implicit parameter to all find-like statements called a projection that specifies what exactly you would like to return.
For instance, showing only adresse1 for all items in your collection:
db.collection.find({},{"coordonnees.adresse1": 1, "_id":0})
should return only the adresse1 parameter. I wasn't quite able to tell exactly what context you're displaying the objects in, but regardless of context, api calls to mongo should be fairly straightforward to make. Let me know if I've misinterpreted this question though.
In your posted example, you should change your find function to something like the following:
Objet.find({params[:id]}, {:fields => [coordonnees.adresse1]})
Hope that helps.
I found the solution to my problem.
To display only one element of the hash, I can do :
<%= #objet.coordonnees['adresse1'] %>
I am not sure if you are using embeds_one or embeds_many as you are using singular and plural forms of the relation name interchangeably in your question.
If it is a embeds_one the problem is that you should not iterate on #objet.coordonnee as it is a single document. Your view code should look like:
<%= #objet.nom %>
<%= #objet.coordonnee.address1 %>
If it is a embeds_many, your relation name should be plural, then you should be able to use t.address1 in your view.
# model Objet
embeds_many :coordonnees
# view
<%= #objet.nom %>
<% #objet.coordonnees.each do |t| %>
<%= t.address1 %>
<% end %>

Check if an attribute is validated

My problem is as follows:
I've got a form view, which needs to display success and failure icons after submit.
Before submit it just needs to show the form without the success and failure icons.
We can do this in several ways when this is the form:
<%= form_for #resource do |f| %>
<div class='<%= set_class #resource, :name %>'>
Name: <%= f.text_field :name %>
</div>
<% end %>
Check if the request is a POST:
def set_class( record, attribute )
if request.post?
if record.errors[attribute].any?
return "FAILED"
else
return "SUCCESS"
end
end
# If not submitted, we don't want a class
end
Set a flag after validation ( We can replace request.post? in above solution with record.tried_to_validate ):
class MyModel < ActiveRecord::Base
after_validation :set_tried_to_validate
attr_accessor :validated
def set_validated
#tried_to_validate = true
end
end
But I don't really like these solutions..
Isn't there an inside Rails method to check if the validation process is done?
You can first test for validity..
#form.valid?
Which will generate errors stored in 'errors' on your #form. To see if errors exist on a specific field,
#form.errors[:some_field]
On your form, you can simply do:
<% if #form.errors[:some_field].empty? %>
Valid
<% end %>
As long as some fields generate errors, the whole form will be !valid?, so you'll revert to showing the form again (:new), and you can should 'Valid' or checkmark.
I think you are looking for something like client side validations, if want the validation to show inline on the form. http://railscasts.com/episodes/263-client-side-validations
EDIT
If you want to capture the 3 stages, you can save in your db. New, Validate, Finished and just use callbacks to save each stage and set the default to new. (You will have the change the data type of the validated attribute to string)
after_validation update attribute to "validate"
after_save update attribute to "Finished"
Then you can use an if elsif else conditions to check for the value of that attribute and render the tick and cross. Obviously, this isn't pretty and you should just use valid? and the errors? helpers.

How to render partial index in Rails3

On my dashboard I'm trying to render a partial as a table (index)
My partial: _transaction.html.erb
That partial is actually an index, based on transactions index. It should return all transactions in a table. My partial contains:
<% #transactions.each do |transaction| %>
<tr>
<td><%= transaction.transaction_type %></td>
<td><%= transaction.date %></td>
</tr>
<% end %>
The error I receive:
"You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.each"
That would seem to indicate that your TransactionsController#index action is not returning anything for #transactions. The most obvious cause is that whatever logic you are using to find records is broken, returning 0 results, or not setting #transactions correctly.
In views like that, you want to do an error check for the situation where you have no results (or an error of some sort).
Your index.html view:
<% if !#transactions || #transactions.length == 0 %>
<p>'No transactions found.'</p>
<% else %>
<table>
<!-- put your column headers here -->
<!-- the next line iterates through each transaction and calls a "_transaction" partial to render the content -->
<%= render #transactions %>
</table>
<% end %>
Your _transaction.html.erb partial:
<tr>
<td><%= transaction.transaction_type %></td>
<td><%= transaction.date %></td>
</tr>
That will get your view working again. The next step is to figure out why your controller action is not returning results. Start by opening a rails console and trying to retrieve records:
>> Transaction.all
If that returns any results, then you have data. If not, create a record either via a web interface you've developed or via the rails console:
>> t = Transaction.new()
>> t.transaction_type = 1 #or whatever is appropriate for your application
>> t.date = Date.today
>> t.valid? #if true, your record will save. If not, you need to fix the fields so they validate
>> t.save
Once you have a record, test your view again. If it still fails, you probably have an error in your controller logic. As to what that error could be, you'll need to post it for us to help you with that. :)