Rails with AngularJS calculations over nested forms - ruby-on-rails

I have a Rails 3.2.8 app in which I'm applying some AngularJS for calculations dynamically within a form.
I have a basic test application which maps an investor to multiple houses and each house has a cost and a value in which I would like to total at the end.
Here is my form
<div ng-controller="InvestorCtrl">
<%= form_for(#investor) do |f| %>
<% if #investor.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#investor.errors.count, "error") %> prohibited this investor from being saved:</h2>
<ul>
<% #investor.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<% i = 0 %>
<%= f.fields_for :houses do |builder| %>
<%= builder.label :address %>
<%= builder.text_field :address %>
<%= builder.label :suburb %>
<%= builder.text_field :suburb %>
<%= builder.label :cost %>
<%= builder.text_field :cost, "ng-model" => "timesheets[#{i}].cost", "ng-change" => "calc_cost()" %>
<%= builder.label :value %>
<%= builder.text_field :value, "ng-model" => "timesheets[#{i}].value" %>
<% i = i + 1 %>
<% end %>
<div class="field">
<%= f.label :total_cost %>
<%= f.number_field :total_cost, "ng-model" => "total_cost" %>
</div>
<div class="field">
<%= f.label :total_value %>
<%= f.number_field :total_value, "ng-model" => "total_value" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
</div>
Here is the angularjs coffeescript I'm using
$ (event) ->
app = angular.module "investor", []
app.controller("InvestorCtrl", ["$scope", ($scope) ->
$scope.timesheets = [
{ cost: 295000, value: 450000 },
{ cost: 600000, value: 620000 },
{ cost: 1000000, value: 900000 },
]
$scope.calc_cost = ->
total = 0
for ts in $scope.timesheets
total = total + ts.cost
$scope.total_cost = total
$scope.calc_cost()
])
angular.bootstrap document, ['investor']
When I load a new form I'm building three houses in the controller like so:
def new
#investor = Investor.new
3.times { #investor.houses.build }
respond_to do |format|
format.html # new.html.erb
format.json { render json: #investor }
end
end
The total cost is calculated correctly when going to a new form, however when I change any of the houses 'cost' values the 'total_cost' field is set to blank.
Am I binding correctly?
Is there an easier way to bind nested forms using AngularJS with Rails templates?
At the moment I'm just trying to get a sum of houses 'cost' value into the 'total_cost' field using AngularJS.

I managed to find my problem using the great debugging tool called 'batarang'
https://github.com/angular/angularjs-batarang
I just had to parseInt the strings:
total = parseInt(total) + parseInt(ts.cost)

Following (simplified code) is what I would do:
In html:
<input ng-model="cost1"/><br>
<input ng-model="cost2"/><br>
total: {{ total_cost() }}
In controller:
$scope.total_cost = function() {
return $scope.cost1 + $scope.cost2;
}
PS: I do not know how one should ballance between RAILS and angularjs, but I would use ng-repeat for putting 3 forms. I think code would be cleaner in that way.

Related

How to get model attributes to save in order?

I'm building a quiz app, to create a quiz I do this:
def new
#quiz = Quiz.new
50.times do
question = #quiz.questions.build
5.times { question.answers.build }
end
end
enter code here
Which uses nested parameters. The problem is, sometimes the quiz doesn't save in order (such as when I create a new quiz OR I update an existing quiz). If I create a quiz in particular order, say Question 1, Question 2, Question 3, I want the questions in that quiz to remain in the same order after I update or create it. Right now, if I update a quiz the order gets jumbled up if I want to show the quiz using something like quiz.questions.each do |question|
I wasn't aware that ruby databases don't enforce order, so how do I make sure that if I create a quiz, the order in which I enter the questions (top to bottom) will always be the order that the questions are presented in?
If you are interested, this is the form I use to create the quiz:
<%= form_for(#quiz) do |f| %>
<% if #quiz.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#quiz.errors.count, "error") %> prohibited this quiz from being saved:</h2>
<ul>
<% #quiz.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class = 'field'>
<%= f.label :difficulty, "Difficulty of Quiz, 1 to 3 with 3 being most difficult" %>
<%= f.text_field :difficulty %>
</div>
<div class="field">
<%= f.label :for_unsubscribed, "Check to have this quiz be visible to logged in but unsubscribed users" %>
<%= f.check_box :for_unsubscribed %>
</div>
<%= f.fields_for :questions do |question_attribute| %>
<div class = 'inner-c'>
<p>
<%= question_attribute.label :content, "Question" %> <span><b><%= question_attribute.index + 1 %></b></span> <br/>
<%= question_attribute.text_area :content, :cols => 100, :rows => 4 %>
</p>
<p>
<%= question_attribute.label :explanation, "Answer Explanation" %> <br/>
<%= question_attribute.text_area :explanation, :cols => 100, :rows => 6 %>
</p>
<%= question_attribute.label :_destroy, "Remove Question"%>
<%= question_attribute.check_box :_destroy %><br/>
<%= question_attribute.label :passage, "Reference Passage" %> <br/>
<%= question_attribute.text_area :passage, :rows => 3, :class => 'passage-input' %>
<%#= question_attribute.label :question_explanation, "Question Explanation" %>
<%#= question_attribute.text_area :question_explanation, :rows => 10 %>
</p>
<%= question_attribute.fields_for :answers do |answer_attribute| %>
<p>
<%= answer_attribute.label :content, "Answer" %>
<%= answer_attribute.text_field :content %>
<%= answer_attribute.label :correct_answer, "Check to indicate correct answer", :class => 'inline' %>
<%= answer_attribute.check_box :correct_answer, :class => 'inline'%>
</p>
<% end %>
</div> <!-- inner-c -->
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

Why do my model attributes save out of order?

This happens particularly often when I try and update a model.
I have a quiz app, and I add a quiz using this form:
<%= form_for(#quiz) do |f| %>
<% if #quiz.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#quiz.errors.count, "error") %> prohibited this quiz from being saved:</h2>
<ul>
<% #quiz.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class = 'field'>
<%= f.label :difficulty, "Difficulty of Quiz, 1 to 3 with 3 being most difficult" %>
<%= f.text_field :difficulty %>
</div>
<div class="field">
<%= f.label :for_unsubscribed, "Check to have this quiz be visible to logged in but unsubscribed users" %>
<%= f.check_box :for_unsubscribed %>
</div>
<%= f.fields_for :questions do |question_attribute| %>
<div class = 'inner-c'>
<p>
<%= question_attribute.label :content, "Question" %> <span><b><%= question_attribute.index + 1 %></b></span> <br/>
<%= question_attribute.text_area :content, :cols => 100, :rows => 4 %>
</p>
<p>
<%= question_attribute.label :explanation, "Answer Explanation" %> <br/>
<%= question_attribute.text_area :explanation, :cols => 100, :rows => 6 %>
</p>
<%= question_attribute.label :_destroy, "Remove Question"%>
<%= question_attribute.check_box :_destroy %><br/>
<%= question_attribute.label :passage, "Reference Passage" %> <br/>
<%= question_attribute.text_area :passage, :rows => 3, :class => 'passage-input' %>
<%#= question_attribute.label :question_explanation, "Question Explanation" %>
<%#= question_attribute.text_area :question_explanation, :rows => 10 %>
</p>
<%= question_attribute.fields_for :answers do |answer_attribute| %>
<p>
<%= answer_attribute.label :content, "Answer" %>
<%= answer_attribute.text_field :content %>
<%= answer_attribute.label :correct_answer, "Check to indicate correct answer", :class => 'inline' %>
<%= answer_attribute.check_box :correct_answer, :class => 'inline'%>
</p>
<% end %>
</div> <!-- inner-c -->
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
A new form would be generated by the controller like so:
def new
#quiz = Quiz.new
50.times do
question = #quiz.questions.build
5.times { question.answers.build }
end
end
Taking advantage of using nested models, where a Quiz has_many Questions which has_many Answers.
The problem is -- when I create a quiz (with 50 questions), then I try and update the quiz afterwards, to fix a mistake for example, The questions move out of order. Question 43 and Question 1 might switch places. I absolutely need the questions to stay in the same order after I update them but I can't figure out how to make this happen. Any ideas?
Generally in RDBMS order is not specified by default, unless you explicitly state it. Therefore if you don't specify the order you can get results in any order an that is an expected behaviour.
But according to your description question 43 swapped with question 1 after an update, so I can think you are ordering them by an updated_at timestamp. Try to order explicitly order questions by id – id is [normally] a PrimaryKey and it never changes, so your questions will stay in order.

How do I submit one param multiple times on rails?

So I have Users and Interests and they are associated with a has_and_belongs_to_many relation through an interests_users table. What I want to do is to let users select 5 interests when they create their account through checkboxes, but I don't now how to submit the same param 5 times in the same form and I am currently submiting it with checkbox, but Interest is not a boolean. The code right now is like this:
<div class = "field">
<%= f.label :interests %><br>
<% all_interests = Interest.all.map{ |f| [f.name, f.id] } %>
<% all_interests.each do |interest| %>
<p> <%= interest[0] %> <%= f.check_box :interests %> <p>
<% end %>
</div>
In view use the flowing
<% for interest in Interest.all %>
<%= check_box_tag "user[interest_ids][]", interest.id, #user.interests.include?(interest) %>
<%= interest.name %>
<% end %>
In controller accept params as following
params.require(:user).permit( { interest_ids:[] })
You should try this code :
<div class = "field">
<%= f.label :interests %><br>
<% Interest.all.each do |interest| %>
<p> <%= interest.name %> <%= f.check_box :interests, { :multiple => true }, interest.id, nil %> </p>
<% end %>
</div>

Select tag rails

I have a view where I need to show a list of pages (I have a model called Page) and then i need the id of the selected page
I have this code in the view
مهمة جديدة
: <%= form_for :task, :url => {:action=>"create", :controller=>"tasks"}, :html => {:class :
=> "nifty_form"} do |f| %>
<% if #task.errors.any? %>
<div id="error_explanation">
<h2>: عذرا لم نستطع استكمال طلبك</h2>
<ul>
<% #task.errors.full_messages.each do |msg| %>
<li style="color:red;"><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label "اسم المهمة" %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label "وصف المهمة" %><br />
<%= f.text_area :description %>
</div>
<div class="actions">
<button><%= link_to 'العودة الى قائمة المهام', project_tasks_path %></button>
<%= f.submit "مهمة جديدة"%>
</div>
<%= select_tag(:page, options_for_select(['a',1])) %>
<% end %>
#pageslist is a 2d array of the form [['pagename', 1], ..]
The question is how can i access the page_id of the selected page in the controller ?
I tried params[:p_id] but it is not working any help please?
This is what I have in the controller:
#task = Project.find(params[:project_id]).tasks.new(params[:task])
#task.update_attributes({:page_id => params[:p_id]})
Assuming that #pagelist is in a format as you described, then in your view:
<%= select_tag(:page, options_for_select( #pagelist )) %>
You had missed it in your example, and provided only 1d array for options_for_select.
With such prepared view your create action will receive page id in:
params[:page]
it's because you had passed :page as a first argument for select_tag.

Rendering one models 'edit form' in anothers 'index view'

I have two models, Teams and Players. On the teams index page I have a list of players that aren't assigned to a team. I'm trying to make a button so that I can click on one of the players with no team and have the 'edit form' of this player show up on the team index page.
This is my current team#index:
= link_to 'New Team', new_team_path
= link_to 'New Player', new_player_path
#teamLists
- #teams.each do |team|
.team
.teamtitle
.teamname
= link_to truncate(team.name, length: 18), edit_team_path(team)
.teammoney
= number_to_currency(team.adjust_money, precision: 0)
%table
%tr.tableheading
%th.namecolumn Player
%th.poscolumn Pos
%th.pricecolumn $
-team.players.each do |player|
%tr
%td.namecolumn= player.name
%td.poscolumn= player.position
%td.pricecolumn= player.price
-(1..(10-team.players.length)).each do |x|
%tr
%td ---
=render template: 'players/edit'
=render 'players/playerlist'
and this is my player#edit
%h1 Nominated Player
= render 'players/form'
= link_to 'Show', #player
= link_to 'Back', players_path
and the players/form
<%= form_for(#player) do |f| %>
<% if #player.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#player.errors.count, "error") %> prohibited this player from being saved:</h2>
<ul>
<% #player.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :position %><br />
<%= f.text_field :position %>
</div>
<div class="field">
<%= f.label :price %><br />
<%= f.number_field :price %>
</div>
<div class="field">
<%= f.label :team_id %><br />
<%= f.select :team_id, Team.all.map { |team| [team.name, team.id] }, { :include_blank => true } %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
At the moment I get this error 'undefined method `model_name' for NilClass:Class' I think its because the form doesn't have access to #player which is defined in the players edit action. Is there a way I can get this to work somehow?
You can reference any partial from another view page, and that's fine. However, like in your case, if that partial you require needs some instance variables (like #player) you'll have to either: A) declare it in the controller of Teams, or B) pass it in to the partial.
So for A), in your Teams controller for action index, just add #player = Player.new or whatever you need it to be.
For B), do:
render :partial => "my_partial", :locals => {:player => Player.new}

Resources