I am creating a Rails app, and I need a form to function in one of my views and submit data to a table without the use of a scaffold (like I usually do).
Now, the place where this comment form is going to appear is in one view within the blog folder. It will need to allow the user to put in their comment, save it to the table, and then return to the same page.
While this is a pretty commonplace error, I am confused because I am specifying two things that seem critical: creating resources in my routes file for the form, and second, using a create method in my controller.
In the blog.html.erb, this happens in this form:
<%= form_for :cements do |f| %>
<div class="form-group">
<div class="field">
<%= f.label :post %><br>
<%= f.text_area :post, class: "form-control" %>
</div>
</div>
<h5 id="username">Username</h5>
<div class="form-group">
<div class="field">
<%= f.text_field :username, class: "form-control" %>
</div>
</div>
<%= f.hidden_field :slug, :id => "hiddenPicker"%>
<div class="actions">
<%= f.submit "Save", class: "btn btn-success-outline" %>
</div>
<% end %>
Then, in my controller, I have a create method that should redirect back to the original page, as I wanted.
blogs_controller.rb
class BlogsController < ActionController::Base
def index
#posts = Post.order('updated_at DESC').all
#comments = Cement.all
end
def blog
#posts = Post.where(slug: params[:id]).all
#comments = Cement.all
end
def create
#cements= Cement.new(story_params)
#cements.save
redirect_to(:back)
end
private
def story_params
params.require(:cements).permit(:username, :post, :slug)
end
end
Good news: the comment form renders in the view. Bad news: when I submit, I am getting this error: No route matches [POST] "/blog".
My expectation is this will be an issue with my Routes file; however, I have a resources method already in there:
Rails.application.routes.draw do
resources :posts
resources :cements
resources :blogs
The naming convention is the same as my controller file, so I am confused why this error is happening. Any ideas?
:cement is not an object it is just a symbol, so how rails will determine where to POST form? If you inspect your form you will see form action as /blog (current page url).
You should either do
<%= form_for :cements, url: cements_path do |f| %>
or
<%= form_for Cement.new do |f| %>
Both of above will generate form action as /cements, which will submit to CementsController create action, But I see in your case you want to submit it to BlogsController so use the appropriate routes(blogs_path). You can use url in second version also.
Related
I've been trying to create a form that would get parameters for multiple models. I have a photo model that belongs to a product model and I want to make it so that when you create a new product you can also upload images that are linked to that product by id.
<%= form_for #product, html:{multipart:true} do |f| %>
<div class="field">
<%= f.label :price %>
<%= f.text_field :price %>
</div>
<%=form_for #photo do |t| %>
<%t.productID = f.id%>
<div class="field">
<%= t.label (:image) %>
<%= t.file_field (:image) %>
</div>
<%end%>
<div class="actions">
<%= f.submit %>
</div>
<%end%>
right now I'm using paperclip for image attachments and the photo model accepts the images as parameters. I've used paperclip before but the product could only have one image connected to it. If I use the form above I get "First argument in form cannot contain nil or be empty" error and it points to where the form_for #photo starts.I have controllers for both with the usual methods of new, create, update, etc. I've routed resources to both product and photos but I'm still pretty new to rails and don't fully understand how this stuff works.
I think what you're trying to do is a good application for nested forms using the fields_for helper.
First, you'll need to ensure that your product model and photo model have the right associations (A product probably has_many photos, and a photo belongs to a product, right?). Then you'll make sure the product class 'accepts nested attributes for photo's which allows you to add attributes to the photos model from a products form.
in products.rb
class Product
has_many :photos
accepts_nested_attributes_for :photos
end
and in photo.rb
class Photo
belongs_to :product
end
Then you'll want to make sure any attributes you need for the photo are white-listed in your product params.
in products_controller.rb
private
def product_params
params.require(product).permit(:first_product_attribute, :second_produtc_attribute, photo_attributes: [:image])
end
Last, you'll create the form using the special helper fields_for
in your view
<%= form_for #product, html:{multipart:true} do |f| %>
<div class="field">
<%= f.label :price %>
<%= f.text_field :price %>
</div>
<%= f.fields_for :photo do |t| %>
<div>
<%= t.label :image %>
<%= t.file_field :image, :multiple => true %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<%end%>
You'll also need to make sure you're actually creating new photo objects in your product's create action:
in products_controller.rb
def create
#product = Product.new(product_params)
if #product.save!
params[:photo]['image'].each do |img|
#photo = #product.photos.create!(:image => img)
end
flash[:success] = 'product saved!'
redirect_to #product
end
end
Some of this is based on my experience doing the same thing but with Carrierwave instead of Paperclip so your specific implementation might be a little different.
I dont think this is a proper method <%t.productID = f.id%>. Maybe try <% t.text_field :productID, value = f.id, type = hidden %> or something along those lines?
heres some docs for the form helper so you know what to put after t.abcd
http://apidock.com/rails/v3.2.3/ActionView/Helpers/FormHelper/form_for
You're getting the
"First argument in form cannot contain nil or be empty"
..error because #photo is nil, you need to set it in your controller #photo = Photo.new.
Also, form tags inside form tags are invalid HTML.
https://www.w3.org/TR/html5/forms.html#the-form-element
Forms
Content model: Flow content, but with no form element
descendants.
You want to use f.fields_for instead. Learn how to use it here here
I have controllers for both with the usual methods of new, create,
update, etc.
You only ever hit one controller and action when you go to a path, say /photos will only hit the photos controller (as configured in your routes.rb). This I think is where you're messing up the #photo variable. Set both in the same controller in order for the view to be able to see both variables.
I'm having an issue very similar to the one asked in this question here: NoMethodError / undefined method `foobar_path' when using form_for However the answer there confuses me.
I went through Michael Hartel's Ruby on Rails tutorial before developing the application I'm working on at the moment, I tried to copy exactly what he did when he created a user model as I created my model. My application is designed to be a database for university professors, so the model I'm using is called "professor" but it's the same concept as "user".
Here is the code for my New.html.erb where is where users go to create a new professor:
<%provide(:title, 'Add a professor') %>
<div class="jumbotron">
<h2> New Professor</h2>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for (#professor) do |f| %>
<%= f.label "First Name" %>
<%= f.text_field :fname %>
<%= f.label "Last Name" %>
<%= f.text_field :lname %>
<%= f.label "School" %>
<%= f.text_field :school %>
<%= f.submit "Add this professor", class: "btn btn-primary" %>
<% end %>
</div>
</div>
</div>
And then here is the code from the Professor_controller.rb
class ProfessorController < ApplicationController
def show
#professor = Professor.find(params[:id])
end
def new
#professor = Professor.new
end
end
When I replace
<%= form_for (#professor) do |f| %>
In new.html.erb with:
<%= form_for (:professor) do |f| %>
It works. The thread I mentioned above said something about adding a route for the controller. My routes.rb looks like this:
Rails.application.routes.draw do
root 'static_pages#home'
get 'about' => 'static_pages#about'
get 'newprof' => 'professor#new'
resources :professor
And I don't believe that in Michael Hartel's book he does anything differently. I'm still very new to Rails so forgive me if this is a bit of an easy question, I've been stuck on it for a few days and I've tried numerous work arounds, using the instance of :professor works but #professor does not and I don't know why.
Within the Rails environment it's very important to be aware of the pluralization requirements of various names. Be sure to declare your resources as plural:
resources :professors
Declaring it in the singular may mess up the automatically generated routes, you'll get thing like professor_path instead of professors_path. You can check what these are with:
rake routes
If you get errors about x_path being missing, check that there's a route with the name x in your routes listing. The most common case is it's mislabeled, a typo, or you've failed to pluralize it properly.
I am making an app in Rails 4. I use Simple Form.
I have a profile model and a qualifications model.
The associations are:
profile.rb
belongs_to :profile
qualifications.rb
has_many :qualifications
I have a form in my profile views, which includes a part of a form from my qualifications view.
profiles#form
<%= simple_form_for(#profile) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<div class="row">
<div class="intpol2">
Your professional qualifications
</div>
<%= render 'qualifications/form', f: f %>
</div>
Qualifications#form
<%= simple_fields_for :qualification do |f| %>
<div class="form-inputs">
<div class="row">
<div class="col-md-6">
<%= f.input :title, :label => "Your award" %>
</div>
<div class="col-md-6">
</div>
</div>
<div class="row">
<div class="col-md-6">
<%= f.input :level, collection: [ "Bachelor's degree", "Master's degree", "Ph.D", "Post Doctoral award"] %>
</div>
<div class="col-md-6">
<%= f.input :year_earned, :label => "When did you graduate?", collection: (Date.today.year - 50)..(Date.today.year) %>
</div>
</div>
Users may have more than one degree. I want to add a field that is a button which says 'add another qualification' and then a new set of the qualification form fields is available.
I found this post which tries to do something slightly different. I don't want 10 blank sets of the form field (it will make the form look too long).
Creating multiple records for a model in a single view in Rails
Is there another way to achieve this?
You'll be looking for a gem called cocoon; you can also watch this Railscast (Nested forms) which is woefully outdated but still explains the structure very well.
The pattern is very simple, but requires some extra parts:
Have an ajax button which calls the controller
The controller needs to return a form and built fields_for
You'll use JS to append the new fields_for to the original form
The biggest problem is the id of your new fields_for - new implementations of this pattern use child_index: Time.now.to_i
I've written about this here.
Here's a new version:
Ajax
Firstly, you need an "Add Qualification" button, which links to your controller through ajax:
#app/views/profiles/_form.html.erb
<%= simple_form_for(#profile) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<div class="row">
<div class="intpol2">Your professional qualifications</div>
<%= render 'qualifications/form', f: f %>
</div>
</div>
<%= button_to "+", new_profile_path, method: :get %>
<% end %>
Controller
This will go through the new controller method, which we should be able to manage to return the specific response for the ajax request:
#app/controllers/profiles_controller.rb
class ProfilesController < ApplicationController
respond_to :js, :html, only: :new
def new
#profile = Profile.new
#profile.qualifications.build
respond_with #profile #-> will invoke app/views/profiles/new.js.erb
end
end
Response
Once your new.js.erb has fired, we need to build the new HTML form, extract the fields_for and append it to your view:
#app/views/profiles/new.js.erb
var fields_for = $("<%=j render "profiles/form" %>").html(); //-> might need tweaking
$(fields_for).appendTo("#new_profile.form-inputs");
child_index
You should also change your qualifications/form to include the child_index:
#app/views/qualifications/form.html.erb
<%= simple_fields_for :qualifications, child_index: Time.now.to_i do ...
Child index is meant to denote the index of the fields_for elements. In our case (since we're making all new records), it doesn't matter. Using Time.now.to_i ensures a totally unique id each time.
Finally, you need to make sure you're calling:
<%= simple_fields_for :qualifications ... %>
... plural
It seems like that you have to use nested form. You have to try your link tutorial because I will use this too. For another tutorial you can use this as reference nested_forms-rails-4.2.
I hope this help you.
I have two models: Schedules and Result.
Schedule has_one Result
Result belongs_to Schedule
Schedules data will be created first and as matches happen, we will create the results for each schedule.
As in the picture above, the Create link will take you to a page where you will create the result for the schedule. I will send the schedule_id of the schedule for which Create button is clicked.
<%= link_to "Create",new_result_url(:schedule_id => schedule.id),{:class => 'btn btn-link btn'}%>
And in the Results#New
def new
#schedule = Schedule.find(params[:schedule_id])
#result = #schedule.build_result
end
And in the View results/new.html.erb
This is where I am stuck or dont know how to submit the result form
for the schedule_id I selected
<div class="row">
<div class="col-md-4">
<%= form_for(#result) do |f| %>
<h3>Enter the result</h3>
<%= f.text_area :result,class:'form-control' %><br />
<%= f.submit "Submit", class: "btn btn-primary" %>
<% end %>
</div>
</div>
You might want to nest result under schedules. In your routes:
resources :schedules do
resource :result
end
And then your controller could look something like this:
class ResultsController < ApplicationController
def create
schedule.create_result(result_params)
end
private
def schedule
Schedule.find(params[:schedule_id])
end
def result_params
params.require(:result).permit(:result)
end
end
This architects your application to reflect your actual information architecture, and you don't have to worry about passing ids through hidden fields.
In your form, add:
<%= f.hidden_field :schedule_id, value: #schedule.id %>
This will pass the id of the parent schedule in with your params. Also, make sure that you permit the parameter schedule_id in your controller.
Also, to make it easier to pass the schedule_id to the results#new page, I'd change the routes file to this:
resources :schedules do
resources :results
end
That way, the route to the results#new page is now new_schedule_result_path(#schedule), which you can use in your link_to.
Edit:
Also, change your form_for to:
<%= form_for[#schedule, #result] do |f| %>
You would need to have #schedule defined in your controller.
I am making a rails application. After a user has registered (I have already created user registration with devise), they can fill out this form that will contain their profile information. I have done this several times, and i can't find what is wrong. Here is the model:
class Information < ActiveRecord::Base
belongs_to :user
end
Here is the controller:
class InformationsController < ApplicationController
def new
#information = Information.new
end
def create
#information = Information.create(params[:information])
redirect_to student_path
end
def index
end
end
And here is the view for the new action.
<div class="span6 offset3 text-center">
<h1>Edit your information</h1>
<%= simple_form_for #information do |f| %>
<%= f.input :skills %>
<%= f.input :looking_for, :label => 'What help do you need?' %>
<%= f.input :my_idea %>
<%= submit_tag "Save", :class => "btn btn-primary btn-large" %>
<% end %>
</div>
Here is the line in the routes file:
resources :informations
I get the following errors which make no sense to me:
undefined method `information_index_path' for #<#:0x007f9c00c7b3e0>
Does anyone know how to fix this? Thanks.
UPDATE:
When I did rake routes, For informations#create, which is what the form should be going to, it has a blank path. There is also informations#index, which is what I guess its going to now. How do I get it to go to informations#create if the path is blank?
Please try yanking out the comments (# signs) in lines 6 and 9 of your view. They might be messing up the ERB processing.
Can you try informations_path? See here.
The problem was with naming the resource information. As information is the same plural as it is singular, it was confusing rails. I renamed the model description and the controller descriptions_controller, and it worked.