I want to set up my models, such that my Posts has_many Comments and Comments has_many Replies. Comments are working fine. But my application starts breaking saying
undefined method `model_name' for "/posts/adas/comments/11/replies":String
when I try to setup the replies for comments. I cannot figure out what's triggering this error. I can add replies from my Rails console, and see them in the view, but adding the form_for tag breaks the code. Can anybody please point out what is the mistake and how I should be routing it?
Posts#show.html.erb
<h2>Comments</h2>
<% #post.comments.each do |comment| %>
<p>
<b><%= comment.username %></b>
<%= comment.name %>
<% if current_user.email == comment.username || current_user.admin? %>
<%= link_to 'Delete', [comment.post, comment],
:confirm => 'Are you sure?', :method => :delete %>
<% end %>
<p style = "text-indent: 3em">
<% comment.replies.each do |reply| %>
<i><%= reply.author %></i>
<%= reply.content %>
<% end %>
<%= form_for [#reply, post_comment_replies_path(#post, comment)] do |f| %>
<%= f.label :reply %>
<%= f.text_field :content %>
<%= f.submit("Reply") %>
<% end %>
<% end %>
</p>
</p>
<h3>Add a comment:</h3>
<%= form_for([#post, #post.comments.build]) do |f| %>
<%= f.label :comment %><br />
<%= f.text_area :name %>
<%= f.submit %>
<% end %>
replies_controller.rb
class RepliesController < ApplicationController
def create
#reply = #comment.replies.create(reply_params)
redirect_to post_path(#post)
end
private
def reply_params
params.require(:reply).permit(:content)
end
end
routes.rb
Rails.application.routes.draw do
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }
root 'welcome#index'
resources :posts do
resources :comments do
resources :replies
end
member do
put "like", to: "posts#upvote"
end
end
end
You're almost there, but you're not passing the parameters in the proper way to get the result that you want. At the moment you're passing in a url string where rails is expecting a resource object, hence the undefined method exception.
form_for(record, options = {}, &block)
The method takes a record and a hash of options that are optional.
The suspect line is
<%= form_for [#reply, post_comment_replies_path(#post, comment)] do |f| %>
The square brackets should only be used to define a resource and its associated resources which are then used to generate a url path. You should also explicitly state your url in the options hash unless it can be inferred from the resources you pass into form_for.
So it should look something like this, keeping with the way you are doing things.
<%= form_for #reply, url: post_comment_replies_path(#post, comment) do |f| %>
That's the case if you want to specify a url in form_for. However, why don't you just allow rails to generate the url for you?
<%= form_for [#post, comment, #reply] do |f| %>
This way rails should handle the routes.
Related
I have a rails 4 app. I have a form for object in which has field_for another model..
<%= form_for object do |f| %>
<%= f.label:name %>
<%= f.text_field :name %>
<%= fields_for :reference do |f2| %>
<%= f2.file_field_tag :file %>
<%end%>
<% end%>
However, I get "Undefined method 'file_field_tag'". Does anyone know if you can upload files via nested form.
I think because you are using form_for not form_tag.
Try to change:
<%= f2.file_field_tag :file %>
to
<%= f2.file_field :file %>
file_field documentation
I'm using ransack to allow users do dynamical searching:
Controller:
#q = Visit.search(params[:q]);
#visits = #q.result(distinct: true)
#q.build_condition
Model:
def self.ransackable_attributes auth_object = nil
(column_names - UNRANSACKABLE_ATTRIBUTES) + (_ransackers.keys)
end
View:
<%= search_form_for #q, url: doctor_visits_path do |f| %>
<%= f.condition_fields do |c| %>
<%= render "condition_fields", f: c%>
<% end %>
<p><%= link_to_add_fields "Add condition", f, :condition %>
<div class="actions"><%= f.submit "Search", {:class => "btn"} %></div>
<% end %>
Partial:
<div class="field">
<%= f.attribute_fields do |a| %>
<%= a.attribute_select({ associations:
[:specialists, :treatment_factors]
},{:class => "form-control"}) %>
<% end %>
<%= f.predicate_select({},{:class => "form-control"}) %>
<%= f.value_fields do |v| %>
<%= v.text_field :value,{:class => "form-control"} %>
<% end %>
<%= link_to "Remove", '#', class: "remove_fields" %>
</div>
I have several boolean attributes in Visits table. When I choose the boolean attribute in the first field, true or false in second (predicate field) and leave the third value field empty, the params are generated correctly, but the sql query is not, the condition is ignored and all the records from the table are returned instead.
What can be the reason?
Add in your model:
Simple version, using PostgreSQL:
ransacker :predicate do
Arel.sql("to_char(\"#{table_name}\".\"predicate\", '99999')")
end
and the same, using MySQL:
ransacker :predicate do
Arel.sql("CONVERT(#{table_name}.id, CHAR(4))")
end
I am using rails 4.1.6 I looked at the active record validations site and follow their direction, but nothing is displayed in the HTML even if there is an error.
However, when I do it in rails console it works.
post = Post.new #create an empty post to test
post.valid? #false
post.errors.messages #this is successfully generate the error message array
However, it doesn't display any error messages in HTML. In fact "#post.errors" doesn't even run
-Ruby code in html
<%= form_for #post, :method => :post do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :url %>
<%= f.text_field :url %>
<%= f.submit "Submit" %>
<% if #errors.any? %>
<ul>
<% #errors.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
<% end %>
-My PostsController
def create
# post = Post.new(title: params[:post][:title], url: params[:post][:url])
post = Post.new(post_params)
if post.save
redirect_to posts_path
else
#errors = post.errors.messages
redirect_to paths_path
end
end
private
def post_params
params.require(:post).permit(:title, :url)
end
-My post model
class Post < ActiveRecord::Base
validates :title, :length => {maximum: 140, minimum:1}, :presence => true
validates :title, :length => {maximum: 2083, minimum:1}, :allow_blank => true
end
When it comes to errors I do like to have a partial so I can keep my errors the same in the whole app like so:
app/views/shared/_errors.html.erb:
<% if object.errors.any? %>
<h5>The <%= t("activerecord.models.#{object.class.to_s.downcase}") %> could not be saved due to the following errors:</h5>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
And then for the views you want the errors to be displayed, just call:
<%= render 'shared/errors', object: #your_object %>
Hope this helps!
thanks for your help. Got some tip from my teacher it work. Simply use flash[:message] and it worked. Sorry for the trouble everyone
-My controller code
def create
post = Post.new(post_params)
if post.save
redirect_to :back
else
flash[:message] = post.errors.messages
redirect_to :back
end
end
-My HTML code
<%= simple_form_for #post, :method => :post do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :url %>
<%= f.text_field :url %>
<%= f.submit "Submit" %>
<%= flash[:message] %>
<% end %>
I am following Ruby on Rails Guides and I have an error in rendering partial when I want to create a new article:
First argument in form cannot contain nil or be empty
Marked error is from partial _form.html.erb located in the same place as index:
<%= form_for #article do |f| %>
index.html.erb has link:
<%= link_to 'New article', new_article_path %>
controller:
def create
#article = Article.new(article_params)
#article.save
redirect_to #article
end
form partial:
<%= form_for #article do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %><br>
</p>
<% end %>
new.html.erb which renders partial:
<h1>New article</h1>
<%= render 'form' %>
<%= link_to 'Back', articles_path %>
your controller needs a new method
def new
#article = Article.new
end
that way there's an #article object that the form_for can reference.
When you follow a new link, the new action is executed and the form is displayed. It's only when the form is submitted that the create action is executed.
For some reason I am unable to get the correct path for my destroy operation of a very simple model. Are my expectations incorrect?
My routes.rb includes:
resources :designs
And my view contains:
<% #designs.each do |design| %>
<%= link_to "Delete", design, :method => :delete %>
<% end %>
Which results in the HTML:
<a data-method="delete" href="/designs.49" rel="nofollow">Delete</a>
Which of course errors on
"No route for [DELETE] for /designs.49"
When I was expecting the rendered HTML to be:
<a data-method="delete" href="/designs/49" rel="nofollow">Delete</a>
Especially considering rake routes shows me:
DELETE /designs/:id(.:format) designs#destroy
My workaround is to replace: link_to "Delete", design... with: link_to "Delete", "/designs/#{design.id}"... (which works fine), but surely I am overlooking something basic, as no one should have to waste this much time to figure out the absolute most fundamental baseline case for a destroy operation.
Your code in the view could read like this using a _path helper:
<% #designs.each do |design| %>
<%= link_to "Delete", design_path(design), :method => :delete %>
<% end %>
But I guess I can see what you're trying to accomplish. To get the show action, you should be able to do this:
<% #designs.each do |design| %>
<%= link_to "Show", design %>
<% end %>
I wonder if this is a bug in Rails? What happens if you do this?
<% #designs.each do |design| %>
<%= link_to "Delete", url_for(design), :method => :delete %>
<% end %>
Try to replacing this in the helper tag.
<%= link_to "Delete", design_path, :method => :delete %>