So, essentially, I have two models, Ticket
class Ticket < ActiveRecord::Base
belongs_to :event
end
And Event:
class Event < ActiveRecord::Base
belongs_to :club
has_many :tickets
accepts_nested_attributes_for :tickets
end
They are associated with each other, and I have done the necessary migrations.
In the events/show view, it shows the event and then at the end I have a link to create a ticket, with this event's name passed as an id:
<%= link_to 'Add tickets', new_ticket_path(:id => #event.name) %>
This renders properly in the new ticket page, I have tested it in the new ticket view with <%= params[:id] %> and it comes up correctly.
The tickets_controller's create method is as follows:
def create
#ticket = Ticket.new(ticket_params)
#ticket.event_id = params[:id]
...
end
But when testing back in the events/show view
<% #tickets = Ticket.all %>
<% #tickets.each do |ticket| %>
<p><%= ticket.event_id %>--</p>
<% end %>
All of the event_id's come up empty.
Any suggestions?
The problem is you're passing the :id param to the new method, and then expecting it to persist to the create method
Params are HTTP-based values -- they don't last longer than a single request. You'll have to either use a nested resource, or set the event_id attribute in your new form:
Route
#config/routes.rb
resources :events do
resources :tickets #-> /events/:event_id/tickets/new
end
This will keep the params[:event_id] param consistent (as it's being passed in the URL), allowing you to use it in your create action like so:
def create
#ticket = Ticket.new(ticket_params)
#ticket.event_id = params[:event_id]
...
end
This is the conventional way to do this
Attribute
If you want to just test your code, you should set the event_id param in your new action form:
<%= form_for [#event, #ticket] do |f| %>
<%= f.hidden :event_id, params[:id] %> #-> sets params[:ticket][:event_id]
<% end %>
This will allow you to set the event_id param in your strong_params method in your create action:
def new
#event = Event.find params[:event_id]
#ticket = Ticket.new
end
def create
#ticket = Ticket.new(ticket_params)
#ticket.save
end
private
def ticket_params
params.require(:ticket).permit(:event_id)
end
Related
I have two associated models: Job and Candidate. The Candidate model is updated when a user applies to a job listing through the candidates 'new' view. Since I've associated Candidate with the Job model, I can't save any new instances of Candidate. I know that I have to pass job_id as a parameter so that any new instance of Candidate references a particular Job, but I just cant figure out what I'm doing wrong. Also, the Job model is associated with the Devise User model, but Candidate is not associated with the User model. Could that be the issue? Thanks in advance.
I've tried a ton of things in my candidates controller, but now I've put it back to how it was before I associated the Candidate model with Job model, so I can start over again as if I just ran the migration to AddJobToCandidate
candidates_controller.rb
class CandidatesController < ApplicationController
def index
#candidates = Candidate.all
end
def new
#candidate = Candidate.new
render layout: false
end
def single
#candidate = Candidate.find(params[:id])
end
def create
#candidate = Candidate.new(candidate_params)
if #candidate.save
redirect_to root_path
else
render "new"
end
end
private
def candidate_params
params.require(:candidate)
.permit(:first_name, :last_name, :email, :cover_letter, :ph, :job_id)
end
end
views/candidates/new.html.erb
<h1>Work at <%= current_user.company %></h1>
<%= simple_form_for #candidate do |form| %>
<%= form.input :first_name, label: "First Name" %>
<%= form.input :last_name, label: "Last Name" %>
<%= form.input :email, label: "Email" %>
<%= form.input :cover_letter, label: "Cover Letter" %>
<%= form.input :ph, label: "Phone Number" %>
<%= form.button :submit %>
<% end %>
routes.rb
Rails.application.routes.draw do
get 'candidates/index'
get 'candidates/new/:id' => 'candidates#new', :as => 'apply'
get 'candidates/single/:id' => 'candidates#single', :as => 'viewcandidate'
get 'jobs/index'
get 'jobs/new'
get 'jobs/listing/:id' => 'jobs#listing', as: 'listing'
get 'jobs/listings', :as => 'careerpage'
get 'jobs/dashboard'
get 'jobs/single/:id' => 'jobs#single', :as => 'viewjob'
devise_for :users, controllers: { sessions: "users/sessions" }
resources :candidates
resources :jobs
root 'jobs#dashboard'
end
views/jobs/listing.html.erb the only view that links to candidates/new.html/erb
<h1><%= #job.title %></h1>
<p><%= #job.description %></p>
<p><%= link_to "Apply", apply_path(#job.id) %></p>
Candidate/Job association migration
class AddJobToCandidate < ActiveRecord::Migration[5.2]
def change
add_reference :candidates, :job, foreign_key: true
end
end
jobs_controller.rb (don't think this is necessary but I'll include anyway)
class JobsController < ApplicationController
before_action :authenticate_user!
def index
#jobs = current_user.jobs.all
end
def dashboard
end
def new
#job = Job.new
end
def listing
#job = Job.find(params[:id])
render layout: false
end
def listings
#jobs = current_user.jobs.all
render layout: false
end
def single
#job = Job.find(params[:id])
#candidates = Candidate.all
end
def create
#job = current_user.jobs.new(job_params)
if #job.save
redirect_to jobs_index_path
else
render "new"
end
end
private
def job_params
params.require(:job)
.permit(:title, :description, :url, :user_id)
end
end
No error is shown, but model is not updated.
One of the things I tried in candidate_controller #create action was:
def create
#candidate = #job.candidates.create(candidate_params)
if #candidate.save
redirect_to root_path
else
render "new"
end
end
and the error I get is 'undefined method `candidates' for nil:NilClass'
Another thing I tried was adding this line in the #create action:
#job = Job.find(params[:id])
and the error I get is 'Couldn't find Job without an ID'
When you arrive at candidate#new you’re just discarding the Job ID. You’re not making it part of the data submitted by the form to be picked up in the create controller.
Given you have completely abandoned RESTful routes, the quickest solution would be to add this to the form:
<%= form.hidden_field :job_id, value: params[:id] %>
However, I highly recommend you look at RESTful routes and nested resources. You have a mess where the ID passed to Candidate#new is the ID of a different model. While you’re at it you may want to reconsider having a candidate belong to a job, what happens when a candidate is interested in multiple jobs? They create a new profile each time? In job sites one would normally have a Job, a Candidate (or User / Profile) and then a JobApplication, which joins the two.
So I have the models contract and employee. And from an employee's show html I want to be able to add a contract for that particular employee.
Here is the line from my show html
<%= link_to 'Add Contract', new_contract_path(#employee) %>
and my create function in contracts controller
def create
puts "HERE IS"
puts params[:id]
puts "END"
#create contract here for employee
end
EDIT
After farhan's suggestions this is now what my code looks like
def new
#contract = Employee.find_by_id(params[:employee_id]).contracts.new
end
def create
#employee = Employee.find_by_id(params[:employee_id])
#contract = Employee.find_by_id(params[:employee_id]).contracts.build(contract_params)
...
end
my new.html
<h1>New Contract</h1>
<%= render 'form', contract: #contract%>
<%= link_to 'Back', employee_contracts_path(employee_id: #employee) %>
and my _form.html
<%= form_for(contract) do |f| %>
...
<% end %>
but if i got to the url empoyees/1/contracts/new rails says
routes
Run rake routes in your terminal and you will see that new_contract_path(#employee) it is looking for a form with action new after submitting that form, it goes to create action. Also, if you want nested routes then it should be
resources :employees do
resources :contracts
end
and you need to create a form named new.html.erb.
Update
After updating your routes.rb, your path helpers will change too,
in your view,
<%= link_to 'Add Contract', new_employee_contract_path(employee_id: #employee) %>
in your controller,
def create
#assuming Employee has_many contracts
contract = Employee.find_by_id(params[:employee_id]).contracts.build(contract_params)
if contract.save
#success case
else
#failure
end
end
def new
#contract = Employee.find_by_id(params[:employee_id]).contracts.new
end
private
def contract_params
#permit required params
end
I have two models one Topic and Topic_Content.
With the following code
Route
resources :topics do
resources :topic_contents
end
Topic
class Topic < ActiveRecord::Base
has_one :topic_content
accepts_nested_attributes_for :topic_content
end
TopicContent
class TopicContent < ActiveRecord::Base
belongs_to :topics
end
Controller
class TopicsController < ApplicationController
def new
#topic = Topic.new
end
def create
# render text: params[:topic].inspect
#topic = Topic.new(topic_params)
#topic.save
end
private
def topic_params
params.require(:topic).permit(:title, topic_content_attributes: [:text])
end
end
View
<%= form_for #topic do |f| %>
<%= f.label 'Topic:' %>
<%= f.text_field :title %>
<%= f.fields_for :topic_contents do |tf| %>
<%= tf.label :text %>
<%= tf.text_area :text %>
<% end %>
<%= f.submit %>
<% end %>
The title will be saved correct in the topic table but the topic_content(text) wouldn't saved in the database, and I couldn't find the problem.
I'm not a Rails expert, but I'm certain you need to build the association in your controller.
In your new and edit actions you need to have:
def new
#topic = Topic.new
#topic_content = #topic.build_topic_content
end
Because this is a has_one/belongs_to you need to have it look that way. If it was a many association you'd build it with something like #topic_content = #topic.topic_contents.build.
I'm pretty sure it's just a matter of building the association in the right controller, which, I believe, for you, is the topic controller.
Your view should be as follow:
f.fields_for :topic_content do |content_fields|
^
I have 3 models:
event
vendor
vendor_relationship
Every event has multiple vendors through that relationship.
Now I want to create a form at /events/1/add_vendors which creates the relationship AND creates the vendor model.
How would I go about doing this?
Thanks for the help!
ensure that you're Event model looks something like this:
attr_accessible :vendor_relationships, :vendor_relationships_attributes
has_many :vendor_relationships
has_many :vendors, :through => :vendor_relationships
accepts_nested_attributes_for :vendor_relationships
your VendorRelationship model looks something like this:
attr_accessible :vendors, :vendors_attributes
has_many :vendors
accepts_nested_attributes_for :vendors
in your EventController:
#event = Event.new(params[:event])
and in your create view, something like:
<% form_for Event.new do |f| %>
<%= f.text_field, :field_for_the_event %>
<% f.fields_for :vendor_relationships do |rf| %>
<%= rf.text_field, :price_maybe? %>
<% rf.fields_for :vendor do |vf| %>
<%= vf.text_field, :name_and_so_on %>
<% end %>
<% end %>
<% end %>
That's one way. Another, probably better user experience would be to allow for selection of vendor from existing vendors or create new. Create new would ajax creation to the VendorController, and on creation, return the vendor's information to the form. Saving the relationship would ajax a call to create the vendor_relationship and display the result.
Hope that sends you down the right direction.
# routes.rb
resources :events do
resources :vendors, :path_names => { :new => 'add_vendors' }
end
# vendors_controller.rb
before_filter :load_event
before_filter :load_vendor, :only => [:edit, :update, :destroy]
def load_vendor
#vendor = (#event ? #event.vendors : Vendor).find(params[:id])
end
def load_event
#event = params[:event_id].present? ? Event.find(params[:event_id]) : nil
end
def new
#vendor = #event ? #event.vendors.build : Vendor.new
...
end
def create
#vendor = #event ? #event.vendors.build(params[:vendor]) : Vendor.new(params[:vendor])
...
end
def edit
...
end
def update
...
end
def destroy
...
end
# View form
<%= form_for([#event, #vendor]) do |f| %>
...
<% end %>
I have a model named Order and another model named Member and when I try to display fields from the Members model in my Orders view it doesn't even show when using the fields_for tag. Heres what my code looks like.
order model
class Order < ActiveRecord::Base
has_many :members
end
member model
class Member < ActiveRecord::Base
belongs_to :order
end
orders controller
class OrdersController < ApplicationController
def new
#order = Order.new
3.times { #order.members.build }
#title = "Order Form"
end
def create
#order = Order.new params[:order]
if #order.save
flash[:notice] = "Your order has been created"
redirect_to orders_path
else
#title = "Order Form"
render 'new'
end
end
end
The issue is in my orders view:
<% for member in #order.members %>
This displays 3 times but the information below doesn't
<% fields_for "...", member do |member_form| %>
<p>
Name: <%= member_form.text_field :name %>
</p>
<% end %>
<% end %>
For some odd reason the information in the fields for tag won't even display once. Am I missing something?
If you find out what I am doing wrong, can you please explain it to me because I am new to rails.
Thanks in advance!
The block given to a fields_for call on a collection will be repeated for each instance in the collection, essentially creating its own loop, so you don't really need to write your own explicit loop "for member in #order.members". Further, you can leverage nested_attributes functionality to enable saving of associated members directly with #order.save:
class Order < ActiveRecord::Base
has_many :members
accepts_nested_attributes_for :members
end
class Member < ActiveRecord::Base
belongs_to :order
end
In the view:
<%= form_for #order do |order_form| %>
...
<%= order_form.fields_for :members do |member_form| %>
Name: <%= member_form.text_field :name %>
<% end %>
<% end %>
And I think your controller create method should work as you have it.
See the API docs for fields_for, especially the One-to-many subsection.
I think you just need to get rid of the "...", in your call to fields_for, as fields for is expecting an object.
Try:
<% fields_for member do |member_form| %>