I would like to combine both values :hours and :minutes and convert them to to_i in seconds. Next is to assign this value (which should be in seconds) to the :time_duration which is a column in the cars db before it creates a new service. The :time_duration is in a hidden_field because there's no reason to render this data in the view.
views
This is my _car_fields.html.erb which is a nested partial inside a view template called, _form.html.erb .
_car_fields.html.erb
<div class="nested-fields">
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %><br>
<%= f.label :hours %>
<%= f.select :hours, '0'..'8' %>
<%= f.label :minutes %>
<%= f.select :minutes, options_for_select( (0..45).step(15), selected: f.object.minutes )%><br>
<%= f.label :price %><br>
<%= f.text_field :price, :value => (number_with_precision(f.object.price, :precision => 2) || 0) %> <br>
<%= f.label :details %><br>
<%= f.text_area :details %></div>
<%= link_to_remove_association "Remove Car", f, class: 'btn btn-default' %>
<%= f.hidden_field :time_duration, value: %>
<br>
<hr>
</div>
_form.html.erb
<%= simple_form_for #service do |f| %>
<div class="field">
<%= f.label "Select service category" %>
<br>
<%= collection_select(:service, :service_menu_id, ServiceMenu.all, :id, :name, {:prompt => true }) %>
<%= f.fields_for :cars do |task| %>
<%= render 'car_fields', :f => task %>
<% end %>
</div>
<div class="links">
<%= link_to_add_association 'Add New Car', f, :cars, class: 'btn btn-default' %>
</div><br>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
controller
services_controller
def new
#service = current_tech.services.build
end
def create
#service = current_tech.services.build(service_params)
respond_to do |format|
if #service.save
format.html { redirect_to #service, notice: 'Service was successfully created.' }
format.json { render :show, status: :created, location: #service }
else
format.html { render :new }
format.json { render json: #service.errors, status: :unprocessable_entity }
end
end
end
private
def service_params
params.require(:service).permit(:name, :service_menu_id, cars_attributes: [:tech_id, :name, :hours, :minutes, :price, :details, :_destroy])
end
models
service.rb
class Service < ActiveRecord::Base
belongs_to :tech
belongs_to :service_menu
has_many :cars, dependent: :destroy
accepts_nested_attributes_for :cars, :reject_if => :all_blank, :allow_destroy => true
end
car.rb
class Car< ActiveRecord::Base
belongs_to :service
belongs_to :tech
has_many :appointments
end
First, you can remove the hidden time_duration field from the form, since it is not needed.
Then, you'll create a before_save method for your car model:
car.rb
class Car < ActiveRecord::Base
belongs_to :service
belongs_to :tech
has_many :appointments
before_save :generate_time_duration
def generate_time_duration
self[:time_duration] = hours.hours.to_i + minutes.minutes.to_i
end
end
What this does: Before the car object is saved, it will run the generate_time_duration method. What this method does is it simply sums the hours.to_i and minutes.to_i and assigns it to the car's time_duration attribute.
Update old DB records
Since you're adding this functionality in your application AFTER records have already been created, here is a quick way to update all of your current records:
In your command line, open a rails console by running the command rails c (or rails console)
In the console, run this command: Car.all.each { |c| c.save! }
This is a quick, one-time fix that will loop through all Car records, save them, and subsequently update their time_duration fields.
Related
I am trying to implement a form that has associated videos when I create a new tutorial. The issue is that my form is not rendering whenever I visit the page. Could anyone help, please?
This is myapp/views/admin/tutorials/new.html.erb
<h2>New Tutorial</h2>
<%= form_for [:admin, #tutorial] do |f| %>
<%= f.label :title %>
<%= f.text_field :title, class: "block col-4 field" %>
<%= f.label :description %>
<%= f.text_area :description, class: "block col-4 field" %>
<%= f.label :thumbnail %>
<%= f.text_field :thumbnail, class: "block col-4 field" %>
<h3>Videos</h3>
<%= f.fields_for :videos do |builder| %>
<%= builder.label :youtube_url %>
<%= builder.text_field :youtube_url, class: "block col-4 field" %>
<%= builder.label :video_id %>
<%= builder.text_field :video_id, class: "block col-4 field" %>
<% end %>
<%= f.submit "Save", class: "mt2 btn btn-primary mb1 bg-teal" %>
<% end %>
This is my Video model
class Video < ApplicationRecord
has_many :user_videos
has_many :users, through: :user_videos
belongs_to :tutorial
validates_presence_of :position
end
And my Tutorial model
class Tutorial < ApplicationRecord
has_many :videos, -> { order(position: :ASC) }, dependent: :destroy
acts_as_taggable_on :tags, :tag_list
accepts_nested_attributes_for :videos
scope :without_classroom, -> { where(classroom: false) }
end
My controller:
class Admin::TutorialsController < Admin::BaseController
def new
#tutorial = Tutorial.new
end
def create
#tutorial = Tutorial.new(tutorial_params)
if #tutorial.save
flash[:success] = "Successfully created tutorial!"
redirect_to tutorial_path(#tutorial)
else
render :new
end
end
def edit
#tutorial = Tutorial.find(params[:id])
end
def update
tutorial = Tutorial.find(params[:id])
if tutorial.update(tutorial_params)
flash[:success] = "#{tutorial.title} tagged!"
end
redirect_to edit_admin_tutorial_path(tutorial)
end
private
def tutorial_params
params.require(:tutorial).permit(:tag_list, :title, :description, :thumbnail)
end
end
The reason nothing's rendered is that the videos association is empty. For example if you add #tutorial.videos.build in the new controller action, then you will get one set of the fields, and if you have multiple videos in the association (whether persisted or not) you would get one set of the fields per video.
This is the Form. All of the fields get passed (and saved) except the one containing the File.
I have checked that using the
render plain: params[:article].inspect method
giving out this (I have entered the value "n" for all fields):
{"country"=>"n", "region"=>"n", "town"=>"n", "street"=>"n", "company"=>"n", "title"=>"n", "content"=>"n"}
I am leaving out superfluous fields here to make the Form shorter:
<%= form_for(#article, html: { multipart: true }) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :country %>
<%= f.text_field :country, :required => true,
placeholder: "enter country" %>
</div>
<%= f.label :content %>
<%= f.text_field :content, :required => true, placeholder: "town..." %>
</div>
</div>
</div>
</div>
<span class="picture">
<%= form_for #article, html: { multipart: true } do |f| %>
<%= f.text_field :title %>
<%= fields_for :pictures do |ff| %>
<%= ff.file_field :picture %>
<% end %>
<% end %>
</div>
I have also tried the slight variation here, but no change
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for
The create method at the Controller is like this:
def create
#article = current_user.articles.build(article_params)
if #article.save
flash[:success] = "Article created!"
redirect_to root_url
else
render 'articles/new'
end
end
and yes, the new method in the Articles controller, is like I was indicated by peers here:
def new
#article = current_user.articles.build
#article.pictures.build
end
The Article Model
class Article < ActiveRecord::Base
belongs_to :user
has_many :pictures
accepts_nested_attributes_for :pictures, allow_destroy: true
And the pictures Model
class Picture < ActiveRecord::Base
belongs_to :article
mount_uploader :picture, PictureUploader
end
Change your <%= fields_for :pictures do |ff| %> to <%= f.fields_for :pictures do |ff| %>
i have 2 model book and wishlist.
and between this 2 model i use many to many relationship.
Below is my model.
class Book < ActiveRecord::Base
has_many :book_wishlist_customizations, dependent: :destroy
has_many :wish_lists ,through: :book_wishlist_customizations
end
class BookWishlistCustomization < ActiveRecord::Base # through table
belongs_to :wish_list
belongs_to :book
end
class WishList < ActiveRecord::Base
has_many :book_wishlist_customizations
has_many :books,through: :book_wishlist_customizations
end
when i delete book from admin side it raise following error.
PG::ForeignKeyViolation: ERROR: update or delete on table "books" violates foreign key constraint "fk_rails_7a6b92667b" on table "wish_lists" DETAIL: Key (id)=(1) is still referenced from table "wish_lists". : DELETE FROM "books" WHERE "books"."id" = $1.
below is my book form.
<%= form_for #book, url: books_path do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.label :stream_id %>
<%= f.collection_select :stream_id, Stream.all, :id, :stream_name, prompt: true %>
</div>
</br>
<div class="field">
<%= f.label :university_board_id, "University" %>
<%= f.collection_select :university_board_id, UniversityBoard.where(category_id: $college_id).all, :id, :name, prompt: true %>
</div>
</br>
<div class="field">
<%= f.label :course_standard_id, "Course & Year" %>
<%=f.select(:course_standard_id, :"Please select" => true)%>
<%=f.select(:year_semester, :"Please select" => true)%>
</div>
</br>
<div class="field">
<%= f.label :college_school_id, "College" %>
<%=f.select(:college_school_id, :"Please select" => true)%>
</div>
</br>
<div class="field">
<%= f.label :subject_id, "Subject" %>
<%=f.select(:subject_id, :"Please select" => true)%>
</div>
</br>
<div class="field">
<%= f.label :book_name, "Book name" %>
<%= f.text_field :book_name %>
</div>
</br>
<div class="actions">
<%= f.submit "Continue", class: "btn btn-primary" %>
</div>
<% end %>
below is my controller:-
class BooksController < ApplicationController
def new
#book = Book.new
$college_id = Category.where(category_name: ['college']).select(:id)
$school_id = Category.where(category_name: ['school']).select(:id)
end
def create
if user_signed_in?
#book = Book.new(book_params)
#last_commision = Commision.last
#book_status = BookStatus.find_by(status_name: "pending")
#book.update_attributes( commision_id: #last_commision.id, book_status_id: #book_status.id, user_id: current_user.id, quantity: "1")
if #book.save
# exit
session[:book_id] = #book.id
# session[:photo_id] = #book_photo.id
redirect_to multi_steps_path
else
respond_to do |format|
format.html { render :new }
format.json { render json: #book.errors, status: :unprocessable_entity }
end
end
else
session[:book_details] = book_params
redirect_to unauthenticated_root_path, notice: "For post your book first login in our system."
end
end
def stream_change_course
#stream_details=CourseStandard.where(stream_id: params[:stream], category_id: $college_id)
render :json => #stream_details
end
def course_change_college_subject
#year_semester=CourseStandard.where(id: params[:course])
#subject_details=Subject.where(course_standard_id: CourseStandard.where(category_id: $college_id))
#college_details=CollegeSchool.where(course_standard_id: CourseStandard.where(category_id: $college_id))
render :json => {:subject => #subject_details,:college => #college_details,:year =>#year_semester}
end
def price_calculate_commission
#final_amount=params[:price].to_i-(params[:price].to_i*Commision.last.percentage)/100
render :json => #final_amount
end
private
def book_params
params.require(:book).permit(:book_id, :user_id, :book_name, :book_condition_id,:price_for_sale, :mrp, :book_auther, :isbn, :description, :publish_year, :edition, :publication, :book_status_id, :quantity, :category_id, :university_board_id, :college_school_id, :course_standard_id, :subject_id, :commision_id, :stream_id, :medium_id,:year_semester) rescue {}
# params.require(:book).permit(:stream_id, :university_board_id, :course_standard_id, :subject_id, :id)
end
def book_photo_params
params.require(:book_photo).permit(:photo) rescue {}
end
end
I'm guessing from your error that your WishList model has a field for book ids. It shouldn't. Your BookWishListCustomization model's book id field and wishlist id field along with the belongs_to and has_many associations your models have now are enough.
I am new to rails and I'm trying the accepts_nested_attributes_for function. I am creating an inventory system and the accepts_nested_attributes_for feature is being used to attach multiple order details to an order. An order must also be associated with store location.
The problem I'm having is the order is being created but no data is being passed to the order details table.
My views are below:
Orders View
<h1>Place An Order</h1>
<%= form_for ([#location, #order]) do |f| %>
<p>
<%= f.label :customer_id %><br />
<%= f.text_field :customer_id %>
</p>
<p>
<h3>Items</h3>
<%= f.fields_for :order_details do |builder| %>
<%= render 'order_detail_fields', :f => builder %>
<% end %>
</p>
<p><%= link_to_add_fields "Add Item", f, :order_details %></p>
<p>
<%= f.submit %>
</p>
<% end %>
Order_details_fields Partial
<p class="fields">
<%= f.label :item_id %><br />
<%= f.text_field :item_id %></br>
<%= f.label :quantity %></br>
<%= f.text_field :quantity %></br>
<%= f.label :cost %></br>
<%= f.text_field :cost %></br>
<%= f.label :discount %><br />
<%= f.text_field :discount %><br />
<%= f.hidden_field :_destroy %>
<%= link_to_function "remove", "remove_fields(this)" %>
</p>
Orders Controller
class OrdersController < ApplicationController
def index
#orders = Order.all
end
def show
#order = Order.find(params[:id])
end
def new
#order = Order.new
#location = Location.find(params[:location_id])
end
def create
#location = Location.find(params[:location_id])
#order = #location.orders.create(order_params)
##order = #order.order_details.create
if #order.save
redirect_to #order
else
render :action => 'new'
end
end
private
def order_params
params.require(:order).permit(:customer_id, order_detials_attributes: [:id, :item_id, :quantity, :cost, :discount])
end
end
Orders Model
class Order < ActiveRecord::Base
belongs_to :location
has_many :order_details, :dependent => :destroy
accepts_nested_attributes_for :order_details, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
Order Details Model
class OrderDetail < ActiveRecord::Base
belongs_to :order
end
Routes
resources :locations do
resources :orders
end
resources :orders do
resources :order_details
end
Any help with this would be greatly appreciated
Build
Looks like everything is right to me - the only problem being the issue #Pavan outlined, which is that when you use accepts_nested_attributes_for, you have to build the associative object, so it can be used in the form:
#app/controllers/orders_controller.rb
Class OrdersController < ApplicationController
def new
#location = Location.find parmas[:id]
#order = Order.find params[:id]
#order.order_details.build
end
end
Although this looks like the only issue you have, there may be other problems (validation on the OrderDetail model as an example (which you don't have)
The only issue with what both I and Pavan have recommended is if you don't build your associative data, the fields_for don't show on the form. If your fields are showing, it may be a different issue, which will be highlighted in the params hash
Nested attributes of join model won't be saved. relation id's seems to be missing. The following error messages are added when the fields get validated:
* Assigned projects user can't be blank
* Assigned projects project can't be blank
The submitted params look like this ( <%= debug(params) %> )
--- !map:ActionController::Parameters
utf8: "\xE2\x9C\x93"
authenticity_token: HrF1NHrKNTdMMFwOvbYFjhJE1ltlKbuz2nsfBYYBswg=
project: !map:ActionController::Parameters
name: Peter Pan
assigned_projects_attributes: !map:ActiveSupport::HashWithIndifferentAccess
"0": !map:ActiveSupport::HashWithIndifferentAccess
position: Group Leader
currency: " Neverland Dollars"
commit: Add Project
action: create
controller: projects
I have 3 models, as followed:
class User < ActiveRecord::Base
has_many :assigned_projects
has_many :projects, :through => :assigned_projects
has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id
end
class AssignedProject < ActiveRecord::Base
belongs_to :user, class_name: "User"
belongs_to :project, class_name: "Project"
attr_accessible :project_id, :user_id, :position, :project_attributes
accepts_nested_attributes_for :project
validates :user_id, presence: true
validates :project_id, presence: true
validates :position, presence: true
end
class Project < ActiveRecord::Base
belongs_to :user
has_many :assigned_projects
has_many :users, :through => :assigned_projects
belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
attr_accessible :name, :creator_id, :currency :assigned_projects_attributes
accepts_nested_attributes_for :assigned_projects
validates :name, presence: true, length: { minimum: 3, maximum: 100 }
validates :currency, presence: true, length: { minimum: 1, maximum: 5 }
validates :creator_id, presence: true
end
So each User can create a Project. He can add any User to the Project through the join model.
Each Project belongs to a User resp. Creator and has_many user through assigned_projects
I want to give each user of a project a "position", which should be saved in the join model: assigned_project :position
the Project controller looks like that:
class ProjectsController < ApplicationController
def new
#project = Project.new
#project.assigned_projects.build(user_id: current_user)
end
def create
#project = current_user.assigned_projects.build.build_project(params[:project])
#project.creator = current_user
if #project.save
redirect_to current_user
else
render 'new'
end
end
end
and the project/new.html.erb form looks like that:
<%= form_for( #project ) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.fields_for :assigned_projects do |ff| %>
<%= ff.label :position %>
<%= ff.text_field :position%>
<% end %>
<%= f.label :currency %>
<%= f.text_field :currency %>
<%= f.submit "Add Project", class: "" %>
<% end %>
UPDATE: current controller & view
def create
#project = Project.new(params[:project])
if #project.save
redirect_to current_user
else
render 'new'
end
end
<%= form_for( #project ) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.hidden_field :creator_id, value: current_user.id %>
<%= f.fields_for :assigned_projects, #project.assigned_projects do |ff| %>
<%= ff.label :position %>
<%= ff.text_field :position%>
<% end %>
<%= f.label :currency %>
<%= f.text_field :currency %>
<%= f.submit "Add Project", class: "" %>
<% end %>
View:
I think you need to pass the objects collection #project.assigned_projects you built in the new action to the fields_for:
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.fields_for :assigned_projects, #project.assigned_projects do |ff| %>
<%= ff.label :position %>
<%= ff.text_field :position%>
<% end %>
<%= f.label :currency %>
<%= f.text_field :currency %>
<%= f.submit "Add Project", class: "" %>
Controller:
If i understood the first line in the create action i think you try to re-build the project assigned_projects in-order to stamp the creator attribute !!
Instead you could remove this line and put a hidden field in the nested for, something like:
<%= ff.hidden_field :creator, current_user %>
So your controller looks pretty basic now:
def create
#project = Project.new(params[:prject])
if #project.save #nested objects will be saved automatically
redirect_to current_user
else
render 'new'
end
end
What does the build_project method do?
I think in your controller you should just have build, not build.build_project, so like this:
#project = current_user.assigned_projects.build(params[:project])
of if build_project is a method used to create the params then
#project = current_user.assigned_projects.build(project_params)
in the case of rails 4 you would need something like this:
def project_params
params.require(:project).permit(:your_params)
end
In the case of rails 3 I think you need to add
attr_accessible :param1, :param2
in the project model for the parameters you want to set.
Problem is solved by removing the validations for project_id and user_id in the join table "AssignedProject"
So the join Model looks like that:
# Join Model AssignedProject
class AssignedProject < ActiveRecord::Base
belongs_to :user#, class_name: "User"
belongs_to :project#, class_name: "Project"
attr_accessible :project_id, :user_id, :position, :project, :project_attributes
accepts_nested_attributes_for :project
validates :position, presence: { message: " can't be blank." }
end
The New and Create methods look like that:
# Projects Controller
class ProjectsController < ApplicationController
def new
#project = Project.new
#project.assigned_projects.build(user_id: current_user)
end
def create
#project = Project.new(params[:project])
if #project.save
#project.assigned_projects.create(user_id: current_user)
redirect_to current_user
else
render 'new'
end
end
end
And the form in the view for the new method looks like that:
<%= form_for( #project ) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.hidden_field :creator_id, value: current_user.id %>
<%= f.fields_for :assigned_projects, #project.assigned_projects do |ff| %>
<%= ff.hidden_field :project_id, value: #project %>
<%= ff.hidden_field :user_id, value: current_user.id %>
<%= ff.label :position %>
<%= ff.text_field :position%>
<% end %>
<%= f.label :currency %>
<%= f.text_field :currency %>
<%= f.submit "Add Project", class: "" %>
<% end %>