Rails map.resources & Helper Urls - ruby-on-rails

I have two models like this:
class Topic < ActiveRecord::Base
has_many :articles
end
class Article < ActiveRecord::Base
belongs_to :user
belongs_to :topic
has_many :comments
end
I have setup the resource mapping like so:
map.resources :topics do |topic|
topic.resources :articles
end
And I can view the articles just fine when I call the appropriate URL (e.g. /:topic_slug/articles/2). In my article's views, I use a partial to handle the creation and editing of the articles, like this:
<% form_for(#article) do |f| %>
...
<% end %>
The problem arrises wen I try to either create a new article or edit an existing one I get the following error:
NoMethodError in Articles#new
Showing app/views/articles/_form.html.erb where line #1 raised:
undefined method `articles_path' for #<ActionView::Base:0x103d11dd0>
Extracted source (around line #1):
1: <% form_for(#article) do |f| %>
2: <%= f.error_messages %>
3:
4: <p>
Trace of template inclusion: app/views/articles/new.html.erb
Does anyone know where I am going wrong and what I am missing?

You need to pass topic also:
<% form_for([#topic, #article]) do |f| %>
When you pass only #article to form_for than it tries to generate correct path based on #article - that's why your error says that you don't have article_path method. When you pass [#topic, #article] to form_for than it will quess that you want to call topic_article_path.
If you don't have any #topic on creating new article, then you probably need to specify new route that accept article without topic, so add:
map.resources :articles
And then:
<% form_for(#article) do |f| %>
will work, but it will generate url like: /articles/3 - without topic part.

If you want a non-nested route for articles, map the articles separately as well:
map.resources :articles

Related

rails form_for ActionView::Template::Error: undefined method `journals_path

I have a journal model for every user.
In routes.rb I have:
resources :users do
resources :journals
end
In user model:
has_many :journals
In journals model:
belongs_to :user
When try to use form_for(journal) I get:
undefined method `journals_path'
I do not know how fix this.
form_for the first line:
<%= form_for(journal) do |f| %>
Since it is a nested resource, you have to include parent user like this:
<%= form_for [#user, #journal] do |f| %>
To get the correct path

undefined method `upload_path' - 'new' action in Ruby on Rails

This should be super simple, but I can't see what I'm doing wrong.
The form in the 'new' page for uploads is getting an error.
'Uploads' belong to 'Event'
'Event' has many 'Uploads'
routes.rb is (as far as I know) correct.
I'm planning on using Refile to upload files to S3 (as per this tutorial... not sure if this is relevant at all though)
Upload.rb
class Upload < ActiveRecord::Base
belongs_to :event
attachment :upload_file
end
Event.rb
class Event < ActiveRecord::Base
has_many :uploads
end
uploads_controller.rb
class UploadsController < ApplicationController
before_action :set_event
def new
#upload = #event.uploads.create
end
private
def set_event
#event = Event.find(params[:event_id])
end
end
Routes.rb
Rails.application.routes.draw do
devise_for :users
root 'pages#home'
resources :events do
resources :coupons
resources :uploads
member do
post :check
end
end
views/uploads/new.html.erb (example)
<%= form_for #upload do |f| %>
<%= f.text_field :name %>
<% end %>
When I navigate to the 'new' page, I get the following error:
undefined method `upload_path' for #<#:0x007fb8709229f0>
Why can't I add a new Upload associated with Event? I know I'm missing something super simple, but I can't put my finger on it.
As uploads is nested in events, you get url for your upload path as follow:
/events/1/uploads/new
In this case, you have to specify #event in your form_for method like this:
<%= form_for [#event, #upload] do |f| %>
Or simply
<%= form_for #event.upload do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end%>

No route matches [POST] "/articles/new"

When I try to submit the form its giving me the error
No route matches [POST] "/articles/new"
the files are: new.html.erb
this file which contains the form with a text field and text area:
<%= form_for :article, url: articles_path do |f| %>
here the url: is to match post request which is a create
form's title
<%= f.label :title %><br>
form's text field
<%= f.text_field :title %></p>
form's title
<%= f.label :text %><br>
form's text area
<%= f.text_area :text %></p>
<p>
<%= f.submit %>
</p>
<% end %>
route file is
Rails.application.routes.draw do
resources :article
end
controller is
the controller with its methods new and create
whenever I submit the form its giving the error, even I used the URL: articles_path which for default post request, I used #articles also in the form but it is giving me the same error. I am new to the Rails so I tried many ways but I could not find the solution
class ArticlesController < ApplicationController
def new #new method which is a get request
end
def create #create method which is a post request
end
end
whenever I submit the form its giving the error, even I used the url: articles_path which for default post request. and I kept
def create
end
in the controller
The reason why this occurs for many people using this tutorial is that they don't reload the form after changing the url option in the form_for helper.
Be sure to reload a fresh copy of the form before trying to submit it (you need the form to have the most recent form submission url).
change:
resources :article
to:
resources :articles #plural
that way it will map to:
articles_path POST /articles(.:format) articles#create
I changed app/views/articles/new.html.erb from:
<%= form_for :article do |f| %>
to:
<%= form_for :article, url: articles_path do |f| %>
You can find the answer on the official guideline.
Because this route goes to the very page that you're on right at the moment, and that route should only be used to display the form for a new article.
Edit the form_with line inside app/views/articles/new.html.erb to look like this:
<%= form_with scope: :article, url: articles_path, local: true do |form| %>
Your actions/methods in the controller do nothing. It should be something like:
class ArticlesController < ApplicationController
def new
#article = Article.new
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
private
def article_params
params.require(:article).permit()# here go you parameters for an article
end
end
In the view:
<%= form_for #article do |f| %>
RedZagogulins answer is right - that is the code you need to use in your articles controller
--
Routes
The clue to your problem is here:
No route matches [POST] "/articles/new"
Typically, when using the correct routing structure:
#config/routes.rb
resources :articles #-> needs to be controller name
You'll find that the new action is GET, not POST. This leads me to believe your system is set up incorrectly (it's trying to send the form data to articles/new, when it should just send to [POST] articles
If you follow the steps outlined by RedZagogulin, it should work for you
I was continually running into this problem and it came down to the fact that I had the following code in my navbar:
<%= link_to "Blog", controller: 'articles' %>
I switched to this and it all started working:
<%= link_to "Blog", articles_path %>
I'm still new to this so the different ways of doing things sometimes gets confusing.
In your case,
at first change the
#/config/routes.rb
resources :article
to
#/config/routes.rb
resources :articles #plural
# Changing this in Plural naming if your file name
# in #/app/view
# is plural
# (ex: /app/view/articles)
#
# and controller and it's class is also in plural naming
# (ex:
# in #/app/controllers/articles_controller.rb file
# class ArticlesController < ApplicationController
#
# end)
In some cases, we need to add a Post routes to make a Post Request of the form. Just add the lines in routes file:
#/config/routes.rb
Rails.application.routes.draw do
resources :articles #plural
post '/articles/new' => 'articles#create'
end
In order to get this working, I needed to combine instructions for two answers. First, I added a specific route in routes.rb to handle POST requests to '/articles/new':
Rails.application.routes.draw do
root "articles#index"
resources :articles
post '/articles/new' => 'articles#create'
end
And then I had to change the first line of the form to this <%= form_with model: #aricle do |form| %>:
<h1>New Article</h1>
<%= form_with model: #aricle do |form| %>
<p>
<%= form.label :title %><br>
<%= form.text_field :title %>
</p>
<p>
<%= form.label :body %><br>
<%= form.text_area :body %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>

nested resources and build method for making association

I have three models associated between: User, Post, Comment. Comment is nested resource with Post.
routes.rb
resources :posts do
resources :comments
end
User model:
has_many :comments
Post model:
has_many :comments
Comment model:
belonsg_to :user
belonsg_to :post
The goal is when User makes new Comment it creates association with that user. So you can see it like User knows all comments he has made.
comments_controller.rb
def create
#post = Post.find(params[post_id]
#comment = #post.comments.build[:comment]
current_user.comments >> #comment
....
end
new.html.erb
<% form_for [#post, #post.comment.build] do |f| %>
.....
<% end %>
This gives me an error no method comments. What should I make to avoid this?
Most likely you are missing "S" letter in new.html.erb. Should be comments:
<% form_for [#post, #post.comments.build] do |f| %>
.....
<% end %>
If there is some more logic behind you didn't post let us know. Your create action looks fine. Try to look in console student_id attribute, if its populated with ID than you are fine.cheers.
Use
#post.comments.build
Instead of
#post.comment.build (x)
this should work, if possible move this line of code from view to controller
for more info
http://guides.rubyonrails.org/association_basics.html#detailed-association-reference
In new.html.erb file, you are using "s" for build method.
It should be,
<% form_for [#post, #post.comments.build] do |f| %>
.....
<% end %>

How do I use nested attributes with the devise model

I have the same issue as Creating an additional related model with Devise (which has no answer).
I have overridden the devise view for creating a new user and added a company name, I have changed the model to use accepts_nested_attributes_for
There are no errors, but it is not adding the nested record and I don't have a controller where I can modify the request.
I have the following (shortened to make it readable):
routes.rb
map.devise_for :users
map.resources :users, :has_many => :companies
user.rb
has_many :companies
accepts_nested_attributes_for :companies
devise :registerable ... etc
company.rb
belongs_to :user
new.html.erb
...
<% form_for resource_name, resource, :url => registration_path(resource_name) do |f| %>
...
<% f.fields_for :company do |company_form| %>
<p><%= company_form.label :name %></p>
<p><%= company_form.text_field :name %></p>
<% end %>
...
UPDATE:
I didn't add :company to the attr_accessible list in the User model.
You can add the following method to the User model:
user.rb
def with_company
self.companies.build
self
end
And modify the view:
new.html.erb
...
<% form_for [resource_name, resource.with_company], :url => registration_path(resource_name) do |f| %>
...
<% f.fields_for :company do |company_form| %>
...
<% end %>
This way, you'll have the nested form to add one company to the user.
To dynamically add multiple companies to the user, check the Railcast #197 by Ryan Bates.
Make sure you are passing the pair of resources as an array, otherwide you will get an error like this: "wrong number of arguments (3 for 2)".
You may be trying to mass assign some protected variable, OR you might not be saving a valid record. Check to make sure that the record is actually saving to the db.
I realised this is a very old thread, but since I found a better solution, hence the reply.
Just change the new.html.erb as follows,
<% form_for(resource, :as => resource_name,:url => registration_path(resource_name) do |f| %>
...
<% prefix = "user[company_attributes]"%>
<% fields_for prefix, #user.company do |company_form| %>
...
<% end %>
<% end %>
This way when #user.save gets invoked, it would run company.save too with all the validations you may have in company model.
I don't have whole lot of RoR experience, but I think this is a better solution. What do you think?

Resources