Ruby on Rails: Remove blank entries in table - ruby-on-rails

I have an app where the user can create a new project and search for previous projects. On the "create new project" page, the user has the option to enter new info for each field, or select from dropdown menus, if the data is already in the database. As for the search function on the search page. The user can search on many different fields, multiple ways.
UPDATE:
Following a suggestion below, I have gone ahead a built a table that holds the many technologies per project.
Search action
def search
#search = params[:client], params[:industry], params[:role], params[:tech_id], params[:business_div], params[:project_owner], params[:status], params[:start_date_dd], params[:start_date_A], params[:start_date_B], params[:keywords]
#project_search = Project.search(*#search).order(sort_column + ' ' + sort_direction).paginated_for_index(per_page, page)
#search_performed = !#search.reject! { |c| c.blank? }.empty?
#project = Project.new(params[:project])
#all_technols = Technol.all
#technol = Technol.new(params[:tech])
params[:technols][:id].each do |technol|
if !technol.empty?
#project_technol = #project.projecttechnols.build(:technol_id => technol)
end
end
respond_to do |format|
format.html # search.html.erb
format.json { render :json => #project }
end
end
New action:
def new
#project = Project.new
#all_technols = Technol.all
#project_technol = #project.projecttechnols.build
#project_technol = Projecttechnol.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #project }
end
end
Create action
def create
#all_technols = Technol.all
#project = Project.new(params[:project])
#technol = Technol.new(params[:tech])
params[:technols][:id].each do |technol|
if !technol.empty?
#project_technol = #project.projecttechnols.build(:technol_id => technol)
end
end
#project.client = params[:new_client] unless params[:new_client].blank?
#project.project_owner = params[:new_project_owner] unless params[:new_project_owner].blank?
#project.tech = params[:new_tech] unless params[:new_tech].blank?
#project.role = params[:new_role] unless params[:new_role].blank?
#project.industry = params[:new_industry] unless params[:new_industry].blank?
#project.business_div = params[:new_business_div] unless params[:new_business_div].blank?
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render json: #project, status: :created, location: #project }
else
format.html { render action: "new" }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
Tech part of the new view:
<%= stylesheet_link_tag "new" %>
<h1>Create New Project</h1>
<div class="tech">
<%#= label_tag :new_tech, "Technologies Used :" %><br/>
<%= text_field_tag :new_tech, nil, :maxlength => 30 %>
Or
<%#= f.select( :tech, Project.all.map {|p| [p.tech]}.uniq, { :prompt => "Select a previous Technology"}, { :multiple => true, :size => 5 }) %>
<!/div>
<% common_techs = [['Mainframe'],['UNIX'],['Windows Servers'],['Networking'],['CISCO'], ['Win7'], ['Telephony'], ['Web services'], ['Website'], ['Cloud'], ['Virtualisation'], ['Data Centre']] %>
<% db_techs = Technol.all.map {|p| [p.tech]}.uniq %>
<% all_tech = common_techs + db_techs %>
<%= fields_for(#project_technol) do |ab| %>
<%= ab.label "Select previous technologies" %><br/>
<%= collection_select(:technols, :id, #all_technols, :id, :tech, {}, {:multiple => true} ) %>
</div>
<% end %>
<%= stylesheet_link_tag "new" %>
<h1>Create New Project</h1>
<div class="tech">
<%#= label_tag :new_tech, "Technologies Used :" %><br/>
<%= text_field_tag :new_tech, nil, :maxlength => 30 %>
Or
<%#= f.select( :tech, Project.all.map {|p| [p.tech]}.uniq, { :prompt => "Select a previous Technology"}, { :multiple => true, :size => 5 }) %>
<!/div>
<% common_techs = [['Mainframe'],['UNIX'],['Windows Servers'],['Networking'],['CISCO'], ['Win7'], ['Telephony'], ['Web services'], ['Website'], ['Cloud'], ['Virtualisation'], ['Data Centre']] %>
<% db_techs = Technol.all.map {|p| [p.tech]}.uniq %>
<% all_tech = common_techs + db_techs %>
<%= fields_for(#project_technol) do |ab| %>
<%= ab.label "Select previous technologies" %><br/>
<%= collection_select(:technols, :id, #all_technols, :id, :tech, {}, {:multiple => true} ) %>
</div>
<% end %>
</div> <%#= small div %>
<% end %>
<div class="back_button2">
<%= button_to "Back", projects_path , :class => "button", :method => "get" %>
</div>
</div> <%#= small div %>
<% end %>
<div class="back_button2">
<%= button_to "Back", projects_path , :class => "button", :method => "get" %>
</div>
Search Page:
<html>
<%= stylesheet_link_tag "search" %>
<body>
<div id ="title1">Exception Database Search</div>
<div id = "search_op">
<%= form_tag search_path, method: :get do %>
<div class="client">
Client :
<%= select(#projects, :client, Project.order("client").map{|p| [p.client]}.uniq, :prompt => "-Any-", :selected => params[:client]) %></br>
</div>
<div class="industry">
Industry :
<%= select(#projects, :industry, Project.order("industry").map {|p| [p.industry]}.uniq, :prompt => "-Any-", :selected => params[:industry]) %></br>
</div>
<div class="role">
Role :
<%= select(#projects, :role, Project.order("role").map {|p| [p.role]}.uniq, :prompt => "-Any-", :selected => params[:role]) %></br>
</div>
<div class="tech">
<% common_techs = [['Mainframe'],['UNIX'],['Windows Servers'],['Networking'],['CISCO'], ['Win7'], ['Telephony'], ['Web services'], ['Website'], ['Cloud'], ['Virtualisation'], ['Data Centre']] %>
<% db_techs = Project.order("tech").map {|p| [p.tech]}.uniq %>
<% all_tech = Project.order("tech").map {|p| [p.tech]} + Project.order("tech").map {|p| [p.tech2]} + Project.order("tech").map {|p| [p.tech3]} + Project.order("tech").map {|p| [p.tech4]} + Project.order("tech").map {|p| [p.tech5]} %>
<%= fields_for(#project_technol) do |ab| %>
<%= collection_select(:technols, :id, #all_technols, :id, :tech, {}, {:multiple => true } ) %>
</div>
<% end %>
<div class="business_div">
Business Division :
<%= select(#projects, :business_div, Project.order("business_div").map {|p| [p.business_div]}.uniq, :prompt => "-Any-", :selected => params[:business_div]) %></br>
</div>
<div class="project_owner">
Project Owner :
<%= select(#projects, :project_owner, Project.order("project_owner").map {|p| [p.project_owner]}.uniq, :prompt => "-Any-", :selected => params[:project_owner]) %></br>
</div>
<div class="date1">
Select start dates from :
<%= select_tag "start_date_dd", options_for_select({
"Select a period" => "",
"3 days ago" => DateTime.now.to_date - 3.days, # = 259_200 sec.
"1 week ago" => DateTime.now.to_date - 1.week, # = 604_800 sec.
"1 month ago" => DateTime.now.to_date - 1.month, # = 2_592_000 sec.
"6 months ago" => DateTime.now.to_date - 6.months, # = 15_552_000 sec.
"1 year ago" => DateTime.now.to_date - 1.year, # = 31_557_600 sec.
}, :selected=>params[:start_date_dd] )%>
</div>
<%#= until now <%= l DateTime.now.to_date %><%#=,%>
<h4> OR</h4>
<div class="date2">
exact start dates
<%= text_field_tag :start_date_A, params[:start_date_A], :style => 'width: 80px;' %>
-
<%= text_field_tag :start_date_B, params[:start_date_B], :style => 'width: 80px;' %></br>
</div>
<div class="status">
Status :
<%= select(#projects, :status, Project.order("status").map {|p| [p.status]}.uniq, :prompt => "-Any-", :selected => params[:status]) %></br>
</div>
<div class="keywords">
Keywords :
<%= text_field_tag :keywords, params[:keywords] %></br>
</div>
<div class="results">
Results per page: <%= select_tag :per_page, options_for_select([10,20,50], :selected=>params[:per_page]), { :onchange => "this.form.submit();"} %></br>
<div class="buttons">
<div id="search_button">
<%= submit_tag "Search", name: nil, :class => "button" %>
</div>
<% end %>
<div class="home_button">
<%= button_to "Home", projects_path, :class => "button", :method => "get" %>
</div>
<div id="reset_button">
<%= button_to "Reset Search", search_path, :class => "button", :method => "get" %>
</div>
</div>
</div> <%#search_op div%>
<div class ="menu"></div>
<div id ="section3">
<% if #project_search.total_entries > 0 %>
<% if #search_performed %>
<% if #search_performed %>
<%= hidden_field_tag :direction, params[:direction] %>
<%= hidden_field_tag :sort, params[:sort] %>
<%= hidden_field_tag :per_page, params[:per_page] %>
<%= hidden_field_tag :page, params[:page] %>
<%= will_paginate (#project_search), :class => 'will' %>
<% end %>
</body>
</html>
Models:
class Projecttechnol < ActiveRecord::Base
attr_accessible :project_id, :technol_id
belongs_to :technol
belongs_to :project
end
class Technol < ActiveRecord::Base
attr_accessible :tech
has_many :projecttechnols
has_many :projects, :through => :projecttechnols
end
class Project < ActiveRecord::Base
attr_accessible :edited_first_name, :edited_last_name, :first_name, :last_name, :business_div, :client, :customer_benifits, :edited_date, :end_date, :entry_date, :financials, :industry, :keywords, :lessons_learned, :project_name, :project_owner, :role, :start_date, :status, :summary, :tech_id
validates_presence_of :business_div, :client, :customer_benifits, :end_date, :financials, :industry, :keywords, :lessons_learned, :project_name, :project_owner, :role, :start_date, :status, :summary#, :tech
validates_format_of :industry, :with => /\A[a-zA-Z]+\z/, :message => "field should only have letters"
validates_format_of :business_div, :with => /\A[a-zA-Z]+\z/, :message => "field should only have letters"
validates_format_of :client, :with => /\A[a-zA-Z]+\z/, :message => "field should only have letters"
validates_format_of :project_owner, :with => /\A[a-zA-Z]+\z/, :message => "field should only have letters"
validates_format_of :role, :with => /\A[a-zA-Z]+\z/, :message => "field should only have letters"
has_many :projecttechnols
has_many :technols, :through => :projecttechnols
def self.like(text); "%#{text}%"; end
def self.search(search_client, search_industry, search_role, search_tech_id, search_business_div, search_project_owner, search_exception_pm, search_status, search_start_date_dd, search_start_date_A, search_start_date_B, search_keywords)
# start with a scoped query, to apply more scopes on it afterwards
_projects = Project.scoped
# then, for each of the parameters, apply the scope only if present
if search_client.present?
_projects = _projects.where ['client LIKE ?', like(search_client)]
end
if search_industry.present?
_projects = _projects.where ['industry LIKE ?', like(search_industry)]
end
if search_role.present?
_projects = _projects.where ['role LIKE ?', like(search_role)]
end
if search_tech_id.present?
_projects = _projects.joins(:technols).where("tech.id" => search_tech_id)
end
if search_business_div.present?
_projects = _projects.where ['business_div LIKE ?', like(search_business_div)]
end
if search_project_owner.present?
_projects = _projects.where ['project_owner LIKE ?', like(search_project_owner)]
end
if search_status.present?
_projects = _projects.where ['status LIKE ?', like(search_status)]
end
todays_date = DateTime.now.to_date
if !search_start_date_A.blank? or !search_start_date_B.blank?
search_start_date_A = Date.parse(search_start_date_A).strftime("%Y-%m-%d")
search_start_date_B = Date.parse(search_start_date_B).strftime("%Y-%m-%d")
todays_date = nil
search_start_date_dd = nil
end
if search_start_date_dd.blank?
todays_date = nil
end
if search_start_date_A.present? or search_start_date_B.present?
_projects = _projects.where [' DATE(start_date) BETWEEN ? AND ?', search_start_date_A, search_start_date_B]
end
if search_start_date_dd.present?
_projects = _projects.where ['DATE(start_date) BETWEEN ? AND ?', search_start_date_dd, todays_date]
end
if search_keywords.present?
_projects = _projects.where ['keywords LIKE ?', like(search_keywords)]
end
# now you have applied only the present scopes. return the result, and watch
# the query as it executes.
_projects
end
def self.paginated_for_index(projects_per_page, current_page)
paginate(:per_page => projects_per_page, :page => current_page)
end
end
I can't seem to get the new technologys on the "new project page" to save in the Technols table. I also can't get the search to work properly. Searching for anything in the technology field returns nothing.

Ok, third question of yours about the same project, it starts to be clear where you want to go.
Have you considered storing technologies in a separate table, and an additional join table for the relationship to the Product table?
This way you can select any number of techs for a project, you can search using only one field (it will get only projects related to the chosen technology) and you won't have such complex code.
Use a select tag to choose the technologies in the project form. Validate the project object if you want it to have at least one technology or similar constraint. Use a select on the whole "Technology" table to do the search box. And use
if search_tech_id.present?
_projects = _projects.joins(:technologies).where("technologies.id" => search_tech_id)
end
instead of all that stuff concatenating LIKEs
EDIT: a way to search for projects related to many techs.
To allow searching for "many techs" you can use a multiselect field. You can also add an option for "AND"-ing or "OR"-ing the conditions (that is, search for porjocets related to all the selected techs or any of the selected techs.
In the controller, when you get the list of tech IDs, to search for projects with ALL the selected techs you have to use some SQL magic:
n_techs = search_techs_ids.size
_projects = _projects.joins(:technologies).
select("projects.*").
where("technologies.id" => search_tech_ids).
group("projects.*").
having("count(technologies.id) = #{n_techs}")
On the other side, to search for ANY tech among the selected ones, you can do
_projects = _projects.joins(:technologies).
where("technologies.id" => search_tech_ids)

Related

Multiple records not available when creating .CSV

#orders should have multiple orders yet when using a respond_to to create an CSV, I only have one order record available in my cvs.erb file. Here's the code.
reports_controller.rb
def orders
params[:q] = {} unless params[:q]
if params[:q][:completed_at_gt].blank?
params[:q][:completed_at_gt] = Time.zone.now.beginning_of_month
else
params[:q][:completed_at_gt] = Time.zone.parse(params[:q][:completed_at_gt]).beginning_of_day rescue Time.zone.now.beginning_of_month
end
if params[:q] && !params[:q][:completed_at_lt].blank?
params[:q][:completed_at_lt] = Time.zone.parse(params[:q][:completed_at_lt]).end_of_day rescue ""
end
params[:q][:s] ||= "completed_at desc"
#search = Order.complete.ransack(params[:q])
#orders = #search.result
respond_to do |format|
format.html
format.csv do
headers['Content-Disposition'] = "attachment; filename=\"Order-List\"#{Date.today}"
headers['Content-Type'] ||= 'text/csv'
end
end
end
order_items.csv.erb
<%- headers = ['Order Number', 'User', 'Item Total', 'Discount Value', 'Sales Total', 'Promotions'] -%>
<%= CSV.generate_line headers %>
<%- #orders.each do |order| -%>
<%= CSV.generate_line([order.number, order.email, order.item_total, order.promo_total, order.total]) %>
<%- end -%>
order_items.html.erb
<%= search_form_for #search, :url => spree.order_items_admin_reports_path do |s| %>
<div class="form-group date-range-filter">
<%= label_tag nil, Spree.t(:date_range) %>
<div class="date-range-filter row">
<div class="col-md-6">
<%= s.text_field :completed_at_gt, :class => 'datepicker datepicker-from form-control', :value => datepicker_field_value(params[:q][:completed_at_gt]) %>
</div>
<div class="col-md-6">
<%= s.text_field :completed_at_lt, :class => 'datepicker datepicker-to form-control', :value => datepicker_field_value(params[:q][:completed_at_lt]) %>
</div>
</div>
</div>
<div class="form-actions">
<%= button Spree.t(:search), 'search' %>
</div>
<%= link_to "Export CSV", order_items_admin_reports_path(format: 'csv', :params[:q] => params[:q]), {:style => 'margin-top: 50px; margin-bottom: 20px;', :class => "btn btn-primary btn-success"} %>
<% end %>

How to write a rspec for update action in view?

Only User with attribute curator equal true can update homepagelist in article to true and it works fine .
<% if #article.homepagelist%>
<% if current_user.curator %>
<%= form_for #article do|f| %>
<%= f.hidden_field :article_id, :value => #article.id%>
<%= f.hidden_field :title, :value => #article.title%>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.hidden_field :body, :value => #article.body%>
<%= f.hidden_field :image, :value => #article.image%>
<%= f.hidden_field :plain_body, :value => #article.plain_body %>
<%= f.hidden_field :magazine_id, :value => #article.magazine_id%>
<%= f.hidden_field :is_sponsored, :value => #article.is_sponsored%>
<%= f.hidden_field :ad_title, :value => #article.ad_title %>
<%= f.hidden_field :homepagelist, :value => false %>
<%= f.submit "Delete from List" %>
<% end %>
<% end %>
<% else %>
<div class="col-md-2"></div>
<% if current_user.curator %>
<%= form_for #article do|f| %>
<%= f.hidden_field :article_id, :value => #article.id%>
<%= f.hidden_field :title, :value => #article.title%>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.hidden_field :body, :value => #article.body%>
<%= f.hidden_field :image, :value => #article.image%>
<%= f.hidden_field :plain_body, :value => #article.plain_body %>
<%= f.hidden_field :magazine_id, :value => #article.magazine_id%>
<%= f.hidden_field :is_sponsored, :value => #article.is_sponsored%>
<%= f.hidden_field :ad_title, :value => #article.ad_title %>
<%= f.hidden_field :homepagelist, :value => true %>
<%= f.submit "Add List" %>
<% end %>
<% end %>
<% end %>
I want to test the update action after i click on add to list or remove from list that change only the homepagelist variable in article to true when i click add to list and to false when i click on rmove from list
describe 'POST #update/homepagelistvariable' do
it 'allows curator to update homepagelist' do
#user = create(:user)
sign_in #user
#user.curator = true
#article2 = create(:article)
#article2.homepagelist = true
patch :update, article: FactoryGirl.attributes_for(:article,
homepagelist:
#article2.homepagelist)
end
end
describe 'PUT #update/homepagelist' do
it 'curator can add article to homepagelist' do
#user = create(:user, :curator => true)
sign_in #user
#article = create(:article, :user_id => #user.id)
put :update, id: #article.id,
article: FactoryGirl.attributes_for(:article,
homepagelist:
'true')
#article.reload
expect(assigns(:article).homepagelist).to match(true)
end
end
it 'curator can remove article to homepagelist' do
#user = create(:user, :curator => true)
sign_in #user
#article = create(:article, :user_id => #user.id,
:homepagelist => true )
put :update, id: #article.id,
article: FactoryGirl.attributes_for(:article,
homepagelist:
'false')
#article.reload
expect(assigns(:article).homepagelist).to match(false)
end
end

A way to get names from ids when in create action

So I have 3 cascading drop down lists - Brand, Year and Model. And I have a Boat model.But boat model is not associated with the 3 cascading drop downs. User selects drop downs and rails #create the boat. The problem is I have the ids of the drop down selected items. My #create is;
def create
#boat = current_user.boats.new(boat_params) if logged_in?
if #boat.save
flash[:success] = "Boat created!"
render 'edit'
else
render 'new'
end
end
and boat_params
def boat_params
params.require(:boat).permit(:brand, :year, :model)
end
When I click next button it saves the ids it is because of the #create action i believe.
Here is #new.html
<% provide(:title, 'List My Boat') %>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#boat) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="col-md-6">
<%= f.label :Brand %>
<%= f.collection_select(:brand, Brand.all, :id, :name, {:prompt => "Select a Brand"}, {:id => 'brands_select'}) %>
</div>
<div class="col-md-6">
<%= f.label :Year %>
<%= f.collection_select(:year, Year.all, :id, :name, {:prompt => "Select a Year"}, {:id => 'years_select'}) %>
</div>
<div class="col-md-6">
<%= f.label :Model %>
<%= f.collection_select(:model, Model.all, :id, :name, {:prompt => "Select a Model"}, {:id => 'models_select'}) %>
</div>
<div class="col-md-6 col-md-offset-3">
<%= f.submit "Next", class: "btn btn-primary"%>
</div>
<% end %>
</div>
</div>
</div>
<script>
$(document).ready(function() {
$('#brands_select').change(function() {
$.ajax({
url: "<%= update_years_path %>",
data: {
brand_id : $('#brands_select').val()
},
dataType: "script"
});
});
$('#years_select').change(function() {
$.ajax({
url: "<%= update_models_path %>",
data: {
year_id : $('#years_select').val()
},
dataType: "script"
});
});
});
</script>
Here is the full #boats controller
class BoatsController < ApplicationController
def new
#boat = Boat.new
end
def create
#boat = current_user.boats.new(boat_params) if logged_in?
if #boat.save
flash[:success] = "Boat created!"
render 'edit'
else
render 'new'
end
end
def show
end
def edit
#boat = Boat.find(params[:id])
end
def update
end
def update_years
# updates year and model based on brand selected
brand = Brand.find(params[:brand_id])
# map to name and id for use in our options_for_select
#years = brand.years.map{|a| [a.name, a.id]}.insert(0, "Select a Year")
#models = brand.models.map{|s| [s.name, s.id]}.insert(0, "Select a Model")
end
def update_models
# updates model based on year selected
year = Year.find(params[:year_id])
#models = year.models.map{|s| [s.name, s.id]}.insert(0, "Select a Model")
end
private
def boat_params
params.require(:boat).permit(:brand, :year, :model)
end
end
It's because f.collection_select(...) takes :id as key for brand, model and year. If you insist on using :name as a key try this:
f.collection_select(:brand, Brand.all, :name, :name, {:prompt => "Select a Brand"}, {:id => 'brands_select'})

Error ActiveRecord::RecordNotFound (Couldn't find Planner without an ID):

There is something wrong with my code, and I couldn't figure out what is it. It's already one day I'm trying to solve this by googling and searching on Stack Overflow.
Errors:
Processing ClassTimingsController#show (for 127.0.0.1 at 2014-02-05 15:27:19) [POST]
Parameters: {"authenticity_token"=>"sRTUkx7slXEX+kmzNl4GbYSIFSyf1WGSP5fRB5+rPzY=",
"batch_id"=>"13", "_"=>"", "action"=>"show", "controller"=>"class_timings"}
[FedenaRescue] AR-Record_Not_Found Couldn't find Planner without an ID
ActiveRecord::RecordNotFound (Couldn't find Planner without an ID):
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1567:in `
find_from_ids'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:616:in `find'
app/controllers/class_timings_controller.rb:103:in `show'
I guess there is some problem with the "class_timings_controller.rb" in show.
def show
#planner = nil
if params[:planner_id] == ''
#class_timings = ClassTiming.find(:all, :conditions=>["planner_id is null and is_deleted = false"])
else
#class_timings = ClassTiming.active_for_planner(params[:planner_id])
#planner = Planner.find params[:planner_id] unless params[:id] == ''
end
respond_to do |format|
format.js { render :action => 'show' }
end
end
What is my mistake?
Below is the code for MVC.
Model (class_timing.rb)
class ClassTiming < ActiveRecord::Base
belongs_to :batch
belongs_to :planner
validates_presence_of :subject_title
validates_uniqueness_of :subject_title, :scope => [:planner_id , :batch_id, :is_deleted]
named_scope :for_batch, lambda { |b| { :conditions => { :batch_id => b.to_i, :is_deleted=>false, :checklist => false} } }
named_scope :default, :conditions => { :batch_id => nil, :checklist => false, :is_deleted=>false }
named_scope :active_for_batch, lambda { |b| { :conditions => { :batch_id => b.to_i, :is_deleted=>false} } }
named_scope :active, :conditions => { :batch_id => nil, :is_deleted=>false }
named_scope :for_planner, lambda { |p| { :conditons => { :planner_id => p.to_i, :is_deleted=>false, :checklist => false} } }
named_scope :default, :conditions => { :planner_id => nil, :checklist => false, :is_deleted=>false }
named_scope :active_for_planner, lambda { |p| { :conditions => { :planner_id => p.to_i, :is_deleted=>false} } }
named_scope :active, :conditions => { :planner_id => nil, :is_deleted=>false }
end
View
index
<div id="content-header">
<%= image_tag("/images/show_timetable.png") %>
<h1><%= t('teaching_schedule') %></h1>
<h3><%= t('create_new_teaching_schedule') %></h3>
<div id="app-back-button">
<%= link_to_function image_tag("/images/buttons/back.png", :border => 0), "history.back()" %>
</div>
</div>
<div id="page-yield">
<div id="flash_box"></div>
<% unless flash[:notice].nil? %>
<p class="flash-msg"> <%= flash[:notice] %> </p>
<% end %>
<div class="label-field-pair">
<label ><%= t('select_a_batch') %>:</label>
<div class="text-input-bg">
<%= select :batch, :id,
#batches.map {|b| [b.full_name, b.id] },
{:prompt => "#{t('common')}"},
{:onchange => "#{remote_function(
:url => { :action => 'show' },
:with => "'batch_id='+value",
:before => "Element.show('loader')",
:success => "Element.hide('loader')"
)}"} %>
<label ><%= t('select_a_module') %>:</label>
<div class="text-input-bg">
<%= select :planner, :id,
#planners.map {|p| [p.name, p.id] },
{:prompt => "#{t('common')}"},
{:onchange => "#{remote_function(
:url => { :action => 'show' },
:with => "'planner_id='+value",
:before => "Element.show('loader')",
:success => "Element.hide('loader')"
)}"} %>
<%= image_tag("loader.gif", :align => "absmiddle", :border => 0, :id => "loader", :style =>"display: none;" ) %>
</div></div></div>
<div id="class-timings-list"><%= render :partial => "show_batch_timing" %></div>
<div id="modal-box" style="display:none;"></div>
<div class="extender"></div>
</div>
show
<div class="linker">
<%= link_to_remote "#{t('add')}", :url => { :action => 'new', :id => #planner , :id => #batch} %>
</div>
<% unless #class_timings.empty? %>
<table id="class-timings-list" width="100%">
<tr class="tr-head">
<td><%= t('subject_title') %></td>
<td><%= t('page_no') %></td>
<td><%= t('duration') %></td>
<td><%= t('checklist') %></td>
<td><%= t('tutor_name') %></td>
<td><%= t('operations') %></td>
</tr>
<% #class_timings.each do |class_timing| %>
<tr id="class-timing-<%= class_timing.id %>" class="tr-<%= cycle('odd','even') %>">
<td class="col-2"><%= class_timing.subject_title %></td>
<td class="col-5" style="text-align:right"><%= class_timing.page_no %></td>
<td class="col-5" style="text-align:right"><%= class_timing.duration %></td>
<td class="col-5" style="text-align:center"><%= check_box_tag(nil, class_timing.checklist, class_timing.checklist, :disabled => true) %></td>
<td class="col-3"><%= class_timing.tutor_name %></td>
<td class="col-3"><small><%= link_to_remote("#{t('edit_text')}",
:url => edit_class_timing_path(class_timing), :method => 'get' ) %> |
<% #tt = PeriodEntry.find_all_by_id(class_timing_id ) %>
<!-- <% #tt = PeriodEntry.find_all_by_class_timing_id(class_timing.id ) %> -->
<% if #tt.empty? %>
<%= link_to_remote("#{t('delete_text')}",
:url => class_timing_path(class_timing),
:method => 'delete',
:confirm => "#{t('confirm_msg')}",
:update => "class-timing-#{class_timing.id}") %>
<% else %>
<s><%= t('delete_text') %></s>
<% end %></small></td>
</tr>
<% end %>
</table>
<% else %>
<h4><%= t('set_in_common') %></h4>
<% end %>
new
<label class="head_label"><%= t('create_new_teaching_schedule_for') %> <br>
<span>
<% if #planner.nil? and #batch.nil? %>
<%= t('common') %>
<% else %>
<%= #planner.name and #batch.full_name %>
<% end %>
</span></label>
<div id="ajax-create">
<% form_remote_for :class_timing,
:url => { :action => 'create'} do |f| %>
<% planner_id = (#planner.nil? ? nil : #planner.id) %>
<% batch_id = (#batch.nil? ? nil : #batch.id) %>
<%= f.hidden_field :planner_id, :value => planner_id %>
<%= f.hidden_field :batch_id, :value => batch_id %>
<div id="form-errors"></div>
<div class="label-field-pair">
<label for="name"><%= t('subject_title') %></label>
<div class="input-field"><%= f.text_field :subject_title %></div>
</div>
<div class="label-field-pair">
<label for="name"><%= t('page_no') %></label>
<div class="input-field"><%= f.text_field :page_no %></div>
</div>
<div class="label-field-pair">
<label for="name"><%= t('duration') %></label>
<div class="input-field"><%= f.text_field :duration %></div>
</div>
<div class="label-field-pair">
<label for="name"><%= t('Completed') %></label>
<div><%= f.check_box :checklist, :checked => false %></div>
</div>
<div class="label-field-pair">
<label for="name"><%= t('tutor_name') %></label>
<div class="input-field"><%= f.text_field :tutor_name %></div>
</div>
<br>
<br>
<br>
<%= f.submit "? #{t('save')}", :class => 'submit-button' %>
<% end %>
</div>
edit
<label class="head_label"><%= t('edit_teaching_schedule_for') %> <br>
<span>
<% if #planner.nil? and #batch.nil? %>
<%= t('common') %>
<% else %>
<%= #planner.name and #batch.name %>
<% end %>
</span></label>
<div id="ajax-edit">
<% form_remote_for #class_timing do |f| %>
<div id="form-errors"></div>
<div class="label-field-pair">
<label for="name"><%= t('subject_title') %></label>
<div class="text-input-bg"><%= f.text_field :subject_title %></div>
</div>
<div class="label-field-pair">
<label for="name"><%= t('page_no') %></label>
<div class="text-input-bg"><%= f.text_field :page_no %></div>
</div>
<div class="label-field-pair">
<label for="name"><%= t('duration') %></label>
<div class="text-input-bg"><%= f.text_field :duration %></div>
</div>
<div class="label-field-pair">
<% if #class_timing.checklist %>
<label for="name"><%= t('Completed') %></label>
<div><%= f.check_box :checklist, :checked => true %></div>
<% else %>
<label for="name"><%= t('Completed') %></label>
<div><%= f.check_box :checklist, :checked => false %></div>
<% end %>
</div>
<div class="label-field-pair">
<label for="name"><%= t('tutor_name') %></label>
<div class="input-field"><%= f.text_field :tutor_name %></div>
</div>
<br>
<br>
<br>
<%= submit_tag "? #{t('save')}", :class => 'submit-button' %>
<% end %>
</div>
Controller (class_timings_controller.rb)
class ClassTimingsController < ApplicationController
before_filter :login_required
filter_access_to :all
def index
#batches = Batch.active
#planners = Planner.active
#class_timings = ClassTiming.find(:all,:conditions => { :planner_id => nil, :batch_id => nil, :is_deleted=>false})
end
def new
#class_timing = ClassTiming.new
#batch = Batch.find params[:id] if request.xhr? and params[:id]
#planner = Planner.find params[:id] if request.xhr? and params[:id]
respond_to do |format|
format.js { render :action => 'new' }
end
end
def create
#class_timing = ClassTiming.new(params[:class_timing])
#planner = #class_timing.planner
#batch = #class_timing.batch
respond_to do |format|
if #class_timing.save
#class_timing.planner.nil? and #class_timing.batch.nil? ?
#class_timings = ClassTiming.find(:all,:conditions => { :planner_id => nil,:batch_id => nil,:is_deleted=>false}) :
#class_timings = ClassTiming.for_batch(#class_timing.batch_id)
#class_timings = ClassTiming.for_planner(#class_timing.planner_id)
# flash[:notice] = 'Teaching schedule was successfully created.'
format.html { redirect_to class_timing_url(#class_timing) }
format.js { render :action => 'create' }
else
#error = true
format.html { render :action => "new" }
format.js { render :action => 'create' }
end
end
end
def edit
#class_timing = ClassTiming.find(params[:id])
respond_to do |format|
format.html { }
format.js { render :action => 'edit' }
end
end
def update
#class_timing = ClassTiming.find params[:id]
respond_to do |format|
if #class_timing.update_attributes(params[:class_timing])
#class_timing.planner.nil? and #class_timing.batch.nil? ?
#class_timings = ClassTiming.find(:all,:conditions => { :planner_id => nil, :batch_id => nil}) :
#class_timings = ClassTiming.for_batch(#class_timing.batch_id)
#class_timings = ClassTiming.for_planner(#class_timing.planner_id)
# flash[:notice] = 'Teaching schedule updated successfully.'
format.html { redirect_to class_timing_url(#class_timing) }
format.js { render :action => 'update' }
else
#error = true
format.html { render :action => "new" }
format.js { render :action => 'create' }
end
end
end
def show
#batch = nil
if params[:batch_id] == ''
#class_timings = ClassTiming.find(:all, :conditions=>["batch_id is null and is_deleted = false"])
else
#class_timings = ClassTiming.active_for_batch(params[:batch_id])
#batch = Batch.find_by_id params[:batch_id] unless params[:batch_id] == ''
end
#planner = nil
if params[:planner_id] == ''
#class_timings = ClassTiming.find(:all, :conditions=>["planner_id is null and is_deleted = false"])
else
#class_timings = ClassTiming.active_for_planner(params[:planner_id])
#planner = Planner.find_by_id params[:planner_id] unless params[:planner_id] == ''
end
respond_to do |format|
format.js { render :action => 'show' }
end
end
def destroy
#class_timing = ClassTiming.find params[:id]
#class_timing.update_attribute(:is_deleted,true)
end
end
I provide all the code to help you figure out better, although I knew some of the code is irrelevant to show.
params[:planner_id] or params[:id]
is not passed properly I guess..
Use Planner.find_by_id params[:planner_id]
You're not passing params[:planner_id] into your controller, therefore it is nil, not ''.
So the else on your conditional is being invoked, and you're calling Planner.find nil.
Change this by calling if params[:planner_id].present? instead.
Try this out:
#planner = Planner.find params[:planner_id] if params[:id].present?
present? will take care of nil, blank, etc.

Ruby on Rails dropdown values not saving

I'm new to RoR and having an issue when trying to save from multiple dropdowns. I have three objects - books, genres, and authors. A book object has a genre and author associated to it, but the issue is I can only manage to save either a genre or author to my book object, and not both. Here's where I'm at:
class Author < ActiveRecord::Base
validates :name, :presence => true
validates :biography, :presence => true
has_many :books
end
class Genre < ActiveRecord::Base
validates :description, :presence => true
has_many :books
end
class Book < ActiveRecord::Base
belongs_to :genre
belongs_to :author
has_many :cartitems
validates :name, :presence => true
validates :price, :presence => true
validates :description, :presence => true
end
Controller:
def create
##book = Book.new(params[:book])
#author = Author.find(params[:author].values[0])
#genre = Genre.find(params[:genre].values[0])
#book = #author.books.create(params[:book])
#one or the other saves, but not both
##book = #genre.books.create(params[:book])
respond_to do |format|
if #book.save
format.html { redirect_to(#book, :notice => 'Book was successfully created.') }
format.xml { render :xml => #book, :status => :created, :location => #book }
else
format.html { render :action => "new" }
format.xml { render :xml => #book.errors, :status => :unprocessable_entity }
end
end
end
Not sure if this will help out or not, but here's what the dropdowns look like in the View:
<div class="field">
<%= f.label :genre %><br />
<%= #items = Genre.find(:all)
select("genre", "description", #items.map {|u| [u.description,u.id]}, {:include_blank => true})%>
Appreciate any help with this.
EDIT - Here's my full form.
<%= form_for(#book) do |f| %>
<% if #book.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#book.errors.count, "error") %> prohibited this book from being saved:</h2>
<ul>
<% #book.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 :price %><br />
<%= f.text_field :price %>
</div>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :genre %><br />
<%= #items = Genre.find(:all)
select("genre", "description", #items.map {|u| [u.description,u.id]}, {:include_blank => true})%>
</div>
<div class="field">
<%= f.label :author %><br />
<%=#items = Author.find(:all)
select("author", "name", #items.map {|u| [u.name,u.id]}, {:include_blank => true}) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Update your select fields to be defined like this:
<div class="field">
<%= f.label :genre %><br />
<%= f.select( :genre_id, Genre.all.map {|u| [u.description,u.id]}, {:include_blank => true}) %>
</div>
<div class="field">
<%= f.label :author %><br />
<%= f.select( :author_id, Author.all.map {|u| [u.name,u.id]}, {:include_blank => true}) %>
</div>
And your controller action should be like this:
def create
#book = Book.new(params[:book])
respond_to do |format|
if #book.save
format.html { redirect_to(#book, :notice => 'Book was successfully created.') }
format.xml { render :xml => #book, :status => :created, :location => #book }
else
format.html { render :action => "new" }
format.xml { render :xml => #book.errors, :status => :unprocessable_entity }
end
end
Also, remove the format.xml calls if you don't need them, they're just cluttering your controller action.
There are lots of different ways to fix your problem, it would help to see exactly what's in your params hash and what your full form looks like, but no matter. Here is one way:
#book = #author.books.create(:genre => #genre)
Here is another (essentially the same thing):
#book = #author.books.create {|book| book.genre = #genre}
You could also instantiate the book separately:
#author = Author.find(params[:author].values[0])
#genre = Genre.find(params[:genre].values[0])
#book = Book.create(:author => #author, :genre => #genre)
My guess is you didn't quite build your form correctly, otherwise your params hash would look similar to this {:book => {:author => 1, :genre => 5}} and you would be able to do this:
#book = Book.create(params[:book])
And you would not look up the author using params[:author], but would instead do params[:book][:author] if you needed to do it at all.

Resources