I am trying to create a booking system in ruby on rails, I want a student to book an instructor. I have used devise and created separate models, instructor and student. When a student is logged in, they are able to pick their instructor which is listed, and press 'Book a lesson' both their IDs are transferred to the lesson new form.
I am having two problems, the button to transfer the chosen instructors ID and the student who is signed in ID, to the lessons new page, for the student to book a lesson time and date.
Instructor#index
<% #instructors.each do |instructor| %>
<%=instructor.id%> : <%= instructor.email %>
<%#= button_to 'Book a lesson', new_lesson_path(instructor_id: instructor) %>
<%= link_to 'Book a Lesson', {controller: :lesson, :action => :new, :instructor_id => #instructor.id} %>
<% end %>
Lessons Controller
# GET /lessons/new
def new
# #lesson = Lesson.new
#instructor = Instructor.find(params[:instructor_id])
#lesson = Lesson.new(student_id: Student.find(session[:student_id]).id)
#lesson.instructor_id = #instructor.id
end
lesson FORM new
<%= form_for(#lesson) do |f| %>
<div class="main-title"> New Lesson for "<%= #lesson.instructor.email %> "</div>
<%= f.hidden_field :instructor_id %>
<%= f.hidden_field :student_id %>
<div class="field">
<%= f.label :lesson_date %><br>
<%= f.date_select :lesson_date %>
</div>
<div class="field">
<%= f.label :lesson_start_time %><br>
<%= f.time_select :lesson_start_time %>
</div>
<div class="field">
<%= f.label :lesson_end_time %><br>
<%= f.time_select :lesson_end_time %>
</div>
<div class="actions">
<%= f.submit "Add a lesson" %>
</div>
<% end %>
enter image description here
Related
I generated a scaffold for a portfolio via the Rails command, rails g portfolio titre:string, thumbnail:string lien:string description:text. I also added FriendlyId to get a better URL, and that's about all. Here is the 'update' action.
def update
if #portfolio.update(portfolio_params)
redirect_to #portfolio, notice: 'Portfolio mis à jour.'
else
render :edit
end
end
However, when trying to update a project in my portfolio, the submit button tries to get to 'portfolio#update' via patch, but puts a '.' instead of a '/' which gives me No route matches [PATCH] "/portfolios.test-1"
For the route, I only have resources :portfolios
edit : added the form
<%= form_for #portfolio, url: portfolios_path(#portfolio) do |f| %>
<% if portfolio.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(portfolio.errors.count, "error") %> prohibited this portfolio from being saved:</h2>
<ul>
<% portfolio.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :titre %>
<%= f.text_field :titre %>
</div>
<div class="field">
<%= f.label :categorie %>
<%= f.text_field :categorie %>
</div>
<div class="field">
<%= f.label :description %>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :thumbnail %>
<%= f.file_field :thumbnail %>
</div>
<div class="field">
<%= f.label :lien %>
<%= f.text_field :lien %>
</div>
<div class="actions">
<%= f.submit 'Enregistrer' %>
</div>
<% end %>
I didn't have any other possibilities that doing #portfolio, url: portfolios_path(#portfolio), otherwise Rails considered that '#portfolio' was nil
edit 2 : added the private 'set_portfolio' params
private
# Use callbacks to share common setup or constraints between actions.
def set_portfolio
#portfolio = Portfolio.friendly.find(params[:id])
end
What's wrong with my app ?
portfolios_path is the collection path.
change it portfolio_path should fix it.
<%= form_for #portfolio, url: portfolio_path(#portfolio) do |f| %>
I guess you are going to use this form for creating new portfolio as well, so change it to <%= form_for(#portfolio) %> should fix it and will also work for both cases. form_for will submit to correct path.
I'm getting the error above when I try to create a a 'mark' for a 'student'. I can't figure out how to pass the :student_id when I create a new mark.
Routes
Rails.application.routes.draw do
resources :students do
resources :marks
end
resources :marks
root 'students#index'
Marks Controller
class MarksController < ApplicationController
def create
#student = Student.find(params[:student_id])
#mark = #student.marks.create(params[:input1, :input2, :input3, :weight1, :weight2, :weight3, :mark1, :mark2, :mark3, :final_mark].permit(:input1, :input2, :input3, :weight1, :weight2, :weight3, :mark1, :mark2, :mark3, :final_mark))
#mark.save
if #mark.save
redirect_to student_path(#student)
else
render 'new'
end
end
def new
#mark = Mark.new
end
private
def set_mark
#mark = Mark.find(params[:id])
end
end
Students Show View
<p id="notice"><%= notice %></p>
<p>
<strong>Student Number</strong>
<%= #student.StudentNumber %>
</p>
<p>
<strong>Project Title</strong>
<%= #student.ProjectTitle %>
</p>
<p>
<strong>Project PDF</strong>
<%= #student.ProjectTitle %>
</p>
<p>
<strong>Reader 1</strong>
<%= #student.Reader1 %>
</p>
<p>
<strong>Reader 2</strong>
<%= #student.Reader2 %>
</p>
<h3> <%= link_to 'Add Mark', new_student_mark_path(#student), class:"btn btn-warning"%> </h3>
<p>
<strong>Reader 3</strong>
<%= #student.Reader3 %>
</p>
<%= link_to 'Edit', edit_student_path(#student) %> |
<%= link_to 'Back', students_path %>
Marks Form
<%= form_for #mark, html: {multipart: true} do |f| %>
<% if #mark.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#mark.errors.count, "error") %> prohibited this grading from being saved:</h2>
<ul>
<% #mark.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label 'Introduction' %><br>
<%= f.text_area :input1 %>
<%= f.number_field :weight1 %>
<%= f.number_field :mark1 %>
</div>
<div class="field">
<%= f.label 'Main' %><br>
<%= f.text_area :input2 %>
<%= f.number_field :weight2 %>
<%= f.number_field :mark2 %>
</div>
<div class="field">
<%= f.label 'Conclusion' %><br>
<%= f.text_area :input3 %>
<%= f.number_field :weight3 %>
<%= f.number_field :mark3 %>
</div>
<div class="actions">
<%= f.submit class:"btn-xs btn-success"%>
</div>
<% end %>
Mark model
class Mark < ActiveRecord::Base
belongs_to :student
end
Student Model
class Student < ActiveRecord::Base
has_many :marks
has_attached_file :document
validates_attachment :document, :content_type => { :content_type => %w(application/pdf) }
end
It's probably something really stupid but if anyone could explain the problem I'd be really grateful.
Thanks
I don't suggest you using hidden fields for this purpose.
You should pass student together with mark into form_for helper and rails will generate proper url for you which will look like: /students/:student_id/marks
In this case it will be possible to extract student_id from params in your action later.
form_for [#student, #mark], html: {multipart: true} do |f|
More information about nested resources:
http://guides.rubyonrails.org/routing.html#nested-resources
http://www.informit.com/articles/article.aspx?p=1671632&seqNum=7
https://gist.github.com/jhjguxin/3074080
UPDATE:
Forgot to mention that in order to make this work you need to pass student instance into your template at new action:
def new
#student = Student.find(params[:student_id])
#mark = #student.marks.build
end
I have model Project and in model have field documents(files). I am using gem dragonfly. When editing a project, how to make the list of current files? At this time on the edit page the list of files fields show: "The file is not selected". I do next:
projects_controller:
def edit
end
def update
if #project.update(project_params)
redirect_to #project
else
render :edit
end
end
private
def set_project
#project = Project.find(params[:id])
end
def set_payment_types
#payment_types = PaymentOption.all
end
def project_params
params.require(:project).permit(:title, :description, :price, :location,
:anonymity, :price_category, :category_id, :skill_list, documents_attributes: [:attachment], payment_option_ids: [])
end
edit.html.erb:
<%= form_for #project do |f| %>
<p>
<%= f.label 'Name' %>
<%= f.text_field :title %>
</p>
<P>
<%= f.label 'Budget' %>
<%= f.text_field :price %>
für
<%= f.select :price_category, Project::PRICE_CATEGORIES %>
</P>
<p>
<%= f.label 'Description' %>
<%= f.text_area :description %>
</p>
<p>
<%= f.label 'Category' %>
<%= f.collection_select :category_id, Category.all, :id, :name %>
</p>
<p>
<%= f.label 'Skills Freelancer (15 pieces) *' %>
<%= f.text_field :skill_list %>
</p>
<p>
<%= f.label 'Location' %>
<%= f.text_field :location %>
</p>
<ul>
<% #payment_types.each do |type| %>
<li><%= check_box_tag 'project[payment_option_ids][]', type.id %>
<%= type.name %>
</li>
<% end %>
</ul>
<p>
<b>Anonymity order</b>
</p>
Setup allows for players to remain anonymous. Note that this may reduce the number of responses.
<p>
<%= f.label 'Place Order anonymously' %>
<%= f.check_box :anonymity %>
</p>
<p>
<%= f.fields_for :documents do |d| %>
<%= render 'document_fields', f: d %>
<% end %>
<div class="links">
<%= link_to_add_association 'add file', f, :documents %>
</div>
</p>
<P>
<%= f.submit 'Edit' %>
</P>
<% end %>
_document_fields.html.erb:
<div class="nested-fields">
<%= f.label :attachment %>
<%= f.file_field :attachment %>
<%= link_to_remove_association "remove file", f %>
</div>
document.rb
class Document < ApplicationRecord
belongs_to :project
dragonfly_accessor :attachment
end
On the edit page the list of files fields show: "The file is not selected", but must be specified current files.
file_field is for uploading new files only, not for displaying what is already in the database. For displaying a list of uploaded files, you should just display the name of the file and/or an image tag with the thumbnail and provide a destroy link.
You can also provide a link to create a new attachment.
edit.html.erb
<div>
<ul>
<%= #project.documents.each do |document| %>
<li>
<%= document.attachment.name %>
<%= link_to "Delete", document_path(document), method: :delete, data: { confirm: 'Are you sure you want to delete this?' } %>
</li>
<% end %>
</ul>
<div class="links">
<%= link_to_add_association 'add file', f, :documents %>
</div>
</div>
Note: I've read a couple posts similar to this. But non of the solutions answer my question
I have two objects, Bid and Moz. When I build my Bid object, everything seems to save okay, except for the Moz objects.
Model
class Bid < ActiveRecord::Base
belongs_to :user
has_many :mozs, :dependent => :destroy
accepts_nested_attributes_for :mozs, :allow_destroy => true
end
class Moz < ActiveRecord::Base
belongs_to :bid
end
Bids::Build Controllers
class Bids::BuildController < ApplicationController
include Wicked::Wizard
steps :intro, :problems, :solutions, :pricing
def show
#bid = Bid.find(params[:bid_id])
render_wizard
end
def update
#bid = Bid.find(params[:bid_id])
#bid.attributes = build_params
4.times { #bid.mozs.build } if step == steps.second
render_wizard #bid
end
def new
#bid = Bid.new
redirect_to wizard_path(steps.first, :bid_id => #bid.id)
end
def build_params
params.require(:bid).permit(:client_name, :intro, :prob1, :prob2, :prob3, :site_feel, :search_phrase, :page_score, :total_links,
:internal_links, :external_links, :competition, :complete, :user_id, :us_company, :philosophy_1,
:philosophy_2, :website_conclusions, :is_onsite_seo, :onsite_seo, :is_ongoing_seo, :ongoing_seo,
:is_ppc, :ppc, :is_social_media, :social_media, :is_google_places, :google_places, :is_adwords_express,
:adwords_express, moz_attributes: [:url, :id, :_destroy]
)
end
private
def finish_wizard_path
root_url
end
end
solutions.html.erb
<%= form_for (#bid), url: wizard_path do |f| %>
<% if #bid.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#bid.errors.count, "error") %> prohibited this bid from being saved:</h2>
<ul>
<% #bid.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<% if #bid.is_onsite_seo? %>
<div class="field">
<%= f.label :onsite_seo %><br>
<%= f.text_area :onsite_seo %>
</div>
<% end %>
<% if #bid.is_ongoing_seo? %>
<div class="field">
<%= f.label :ongoing_seo %><br>
<%= f.text_area :onsite_seo %>
</div>
<% end %>
<div class="field">
<%= f.label :ppc %><br>
<%= f.text_area :ppc %>
</div>
<div class="field">
<%= f.label :social_media %><br>
<%= f.text_area :social_media %>
</div>
<div class="field">
<%= f.label :google_places %><br>
<%= f.text_area :google_places %>
</div>
<div class="field">
<%= f.label :adwords_express %><br>
<%= f.text_area :adwords_express %>
</div>
<%= f.fields_for :mozs do |builder| %>
<%= render partial: "moz_fields", locals: {f: builder} %>
<% end %>
<%= link_to_add_association "Add URL", f, :mozs %>
<div class="actions">
<%= f.submit %>
or <%= link_to "skip this step", next_wizard_path %>
</div>
<% end %>
_moz_fields.html.erb
<div class="field fields">
<%= f.label :url, "Comparative URL" %><br>
<%= f.text_field :url %>
<%= f.hidden_field :destroy %>
<%= link_to_function "remove", "remove_fields(this)"%>
</div>
I don't understand why they won't save. In addition, I noticed something odd -- when I don't use a partial for the nested object and use the f form builder for the #bid object (as opposed to 'builder'), I get an error no method or variable :url, but a Moz object is saved (although, not with any of the desired attributes).
My opinion that you misspelled with permit attrbibutes hash, try to change moz_attributes to mozs_attributes.
params.require(:bid).permit(..., :mozs_attributes: [:url, :id, :_destroy])
If you send the parameter _destroy: 1 through your hidden field
<%= f.hidden_field :destroy %>
you instruct Rails to destroy the child moz object, or in your case, prevent it from being created.
As for the second part of your question, if you inline the partial from this
<%= f.fields_for :mozs do |builder| %>
<%= render partial: "moz_fields", locals: {f: builder} %>
<% end %>
to this
<%= f.fields_for :mozs do |builder| %>
<div class="field fields">
<%= f.label :url, "Comparative URL" %><br>
<%= f.text_field :url %>
<%= link_to_function "remove", "remove_fields(this)"%>
</div>
<% end %>
it won't work, because the model object for the scope f is your #bid, not moz. Bids have no url attribute, hence the error.
With the input fields being created in the wrong form builder scope, you did not actually transmit any attributes for your moz object, and so it was created blank. As a side effect, this also meant not sending the _destroy parameter, so the object was saved.
Instead, inline the partial like this (I renamed builder to moz for clarity):
<%= f.fields_for :mozs do |moz| %>
<div class="field fields">
<%= moz.label :url, "Comparative URL" %><br>
<%= moz.text_field :url %>
<%= link_to_function "remove", "remove_fields(this)"%>
</div>
<% end %>
I create a new user with basic fields as user name and password. Then I redirect to another page where the user is allowed to complete his profile. The page looks like this.
Ok, I created the user first. Then I redirected the user to complete his profile. The profile page looks like this
<h1>User successfully created</h1>
<h3>Would you like to complete your profile now?</h3>
<%= render #profile %>
<%= render #address %>
<%= button_to 'Save',{
:controller => "users",
:action => "update",
:id => #user.id,
:profile => #profile,
:address => #address
}, :method => :put %>
The code above executes the update action in the controller. However, I am getting nil for the #profile and #address objects. I guess the button_to is having no effect on the profile and address partials.
The address partial looks as follows
<%= form_for(#address) do |f| %>
<% if #address.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#address.errors.count, "error") %> prohibited this address from being saved:</h2>
<ul>
<% #address.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<fieldset>
<legend>Addresss</legend>
<div class="field">
<%= f.label :street_address %>
<%= f.text_field :street_address, :size => 40 %>
</div>
<div class="field">
<%= f.label :street_address_2 %>
<%= f.text_field :street_address_2, :size => 40 %>
</div>
<div class="field">
<%= f.label :city %>
<%= f.text_field :city, :size => 40 %>
</div>
<div class="field">
<%= f.label :state %>
<%= f.text_field :state, :size => 40 %>
</div>
<div class="field">
<%= f.label :zip_code %>
<%= f.text_field :zip_code, :size => 40 %>
</div>
<% end %>
I would appreciate if anyone would be able to help me on this.
The button_to method only creates a button which an be used to call an controller/ go to another page.
If you want to allow the user to modify fields, you need to use a form. Please read this guide on forms for more information, especially part 2 is of interest for your situation I guess.
Edit: You need a submit button in your form to submit it, not a button_to outside the form. If you want to have both partials submitted at the same time, you need 1 big form and a controller which is able to process the data of both models.