When I click on Delete link for a post on Posts Index page, I keep getting GET request for Show action rather than calling Destroy action. So the error read Unknown action - The action 'show' could not be found for PostsController
I think the problem is something to do with the fact that I have nested routes rather than regular routes.
I look at many posts on Google and StackOverflow, but none of the answers helped me out. Any suggestions?
app/views/posts/index.html.erb
<% #posts.each do |post| %>
<tr>
<td><%= post.content %></td>
<td>Username_placeholder</td>
<td><%= post.created_at %></td>
<td><%= link_to 'Delete', topic_post_path(#topic, post), confirm: 'Are you sure?', method: :delete %></td>
<!-- topic_post_path(#topic,post) -->
</tr>
<% end %>
app/controllers/posts_controller.rb
def index
#topic = Topic.find(params[:topic_id])
#forum = Forum.find_by_id(#topic.forum_id)
#posts = #topic.posts.all
end
def destroy
#post = Post.find(params[:id])
#post.destroy
redirect_to root_path
end
app/models/topic.rb
class Topic < ActiveRecord::Base
has_many :posts, :dependent => :destroy
belongs_to :forum
accepts_nested_attributes_for :posts, :allow_destroy => true
attr_accessible :name, :last_post_id, :posts_attributes
end
app/models/post.rb
class Post < ActiveRecord::Base
belongs_to :topic
attr_accessible :content
end
config/routes.rb
Minforum::Application.routes.draw do
root :to => "forums#index"
resources :forums do
resources :topics
end
resources :topics do
resources :posts
end
end
all the routes
root / forums#index
forum_topics GET /forums/:forum_id/topics(.:format) topics#index
POST /forums/:forum_id/topics(.:format) topics#create
new_forum_topic GET /forums/:forum_id/topics/new(.:format) topics#new
edit_forum_topic GET /forums/:forum_id/topics/:id/edit(.:format) topics#edit
forum_topic GET /forums/:forum_id/topics/:id(.:format) topics#show
PUT /forums/:forum_id/topics/:id(.:format) topics#update
DELETE /forums/:forum_id/topics/:id(.:format) topics#destroy
forums GET /forums(.:format) forums#index
POST /forums(.:format) forums#create
new_forum GET /forums/new(.:format) forums#new
edit_forum GET /forums/:id/edit(.:format) forums#edit
forum GET /forums/:id(.:format) forums#show
PUT /forums/:id(.:format) forums#update
DELETE /forums/:id(.:format) forums#destroy
topic_posts GET /topics/:topic_id/posts(.:format) posts#index
POST /topics/:topic_id/posts(.:format) posts#create
new_topic_post GET /topics/:topic_id/posts/new(.:format) posts#new
edit_topic_post GET /topics/:topic_id/posts/:id/edit(.:format) posts#edit
topic_post GET /topics/:topic_id/posts/:id(.:format) posts#show
PUT /topics/:topic_id/posts/:id(.:format) posts#update
DELETE /topics/:topic_id/posts/:id(.:format) posts#destroy
topics GET /topics(.:format) topics#index
POST /topics(.:format) topics#create
new_topic GET /topics/new(.:format) topics#new
edit_topic GET /topics/:id/edit(.:format) topics#edit
topic GET /topics/:id(.:format) topics#show
PUT /topics/:id(.:format) topics#update
DELETE /topics/:id(.:format) topics#destroy
Related
I need some advice on building a has many through relationship between USER, THING and EXTRA models.
My USER model is slightly modified inside Devise gem and is noted as Creator whereas other models belonging to USER receive :created_things form.
In my app, USERS create THINGS can later add EXTRAS to their THINGS.
I chose has many through because I want to have unique data on all three models and be able to call both THINGS and EXTRAS from the USER "CREATOR" model.
I have built this many different ways and after 10 years of solving my problems by reading stackoverflow, I am finally submitting this request for support! Thank you for your help.
I have tried creating user and extra references on the THING model and declaring nested attributes in the USER and THING model. I have tried several examples from stackoverflow inside the create and new methods but nothing seems to work.
class User < ApplicationRecord
has_many :created_things, class_name: Thing, foreign_key:
:creator_id, :dependent => :destroy
has_many :extras, through: :created_things
accepts_nested_attributes_for :extras, :reject_if => :all_blank,
allow_destroy: true
class Thing < ApplicationRecord
belongs_to :creator, class_name: User
has_many :extras
accepts_nested_attributes_for :extras, :reject_if => :all_blank,
allow_destroy: true
class Extra < ApplicationRecord
belongs_to :creator, class_name: User, inverse_of: :thing
belongs_to :created_things
Members Index.html.erb
<% if thing.extras.exists? %>
<% thing.extras.each do |extra| %>
<%= extra.title %> <%= link_to "[+]", edit_extra_path(extra) %>
<% end %>
<% else if thing.extras.empty? %>
<%= link_to "+1 EXTRA", new_extra_path(current_user) %>
<% end %>
<% end %>
class MembersController < ApplicationController
before_action :authenticate_user!
def index
#user = current_user
#created_extras = #user.extras
#created_things = #user.created_things
end
class ExtrasController < ApplicationController
def new
#extra = Extra.new
end
def create
#extra = current_user.extras.build(extra_params)
if #extra.save
I am able to create a new EXTRA but the :thing_id remains nul as it does not display when called on the show extra view. Therefore I am not surprised that when I return to the member index page that my thing.extras.exists? call is returning false and the created extra never displays under the THING view. My attempts to modify the extra controller have failed and I some of my reading sugested the extras controller is not necessary in this relationship so I am really at a loss on how this is built. I'm assuming I am missing something in new and create methods maybe in things or user controller? Perhaps I'm missing something in routes resources? Any advice is greatly appreciated. Thank you.
Ok, I figured it out. I really didn't need has many through for this model and I did a lot of testing of the syntax on each model.rb and in the end was able to figure it out from this stackoverflow . . .
[Passing parent model's id to child's new and create action on rails
Here are my the various parts of setting up a has many and belongs to relationship with nested attributes.
class Thing < ApplicationRecord
belongs_to :creator, class_name: User
has_many :extras, inverse_of: :thing, :dependent => :destroy
accepts_nested_attributes_for :extras, allow_destroy: true
class Extra < ApplicationRecord
belongs_to :thing, inverse_of: :extras
extras_controller.rb
class ExtrasController < ApplicationController
def new
#extra = Extra.new(thing_id: params[:thing_id])
end
def create
#user = current_user
#extra = Extra.new(extra_params)
#extra.user_id = #user.id
if #extra.save
flash[:success] = "You have added a new Extra!"
redirect_to #extra #extras_path later
else
flash[:danger] = "The form contains errors"
render :new
end
end
edit.html.erb things
<% if #thing.extras.exists? %>
<p>current extras associated with <%= #thing.title %>: </p>
<% #thing.extras.each do |extra| %>
<p><%= extra.title %> <%= link_to "[+]", edit_extra_path(extra) %>
/ <%= link_to "[-]", extra_path(extra), method: :delete %> </p>
<% end %>
<% end %>
<%= link_to "+1 EXTRA", new_extra_path(thing_id: #thing.id) %>
<%= render 'things/form' %>
I have a nested resource model in my Rails 3 app. It is the standard blog app with posts and comments. I have just started using jQuery etc to make my app more dynamic, I am now struggling to remove comments in the nested model with the link_to helper.
Comments Model
class Comment < ActiveRecord::Base
belongs_to :post
end
Post Model
class Post < ActiveRecord::Base
has_many :comments, :dependent => :destroy
accepts_nested_attributes_for :comments
end
In my Posts/show.html.erb I have the following bloc that displays all the comments with a link_to helper to delete the comments. This works with HTML but when I added :remote => true, it deleted the parent post instead of the comment! How can I set it up so it deletes only the comment?
<% #post.comments.each do |comment| %>
<%= comment.body %>
<%= link_to "Approve", [#post,comment], :method =>:put, :remote=>true %>
<%= link_to "Delete", [#post,comment], :method =>:delete, :remote=>true %>
<%end%>
Thanks,
I think you want to have this in your delete action of your Comment class:
def delete
...
respond_to do |format|
format.html
format.js
end
end
Then, in your views/comments directory, you should have a file named delete.js.erb that does your jQuery DOM manipulation (finds the particular comment that you clicked the delete link of and remove it.
Then, your link_to for the delete method in your Posts/show.html.erb file, you can specify the controller and action, and also pass in any data you might need (the parent post so you can refer to it in your jQuery). You can refer to the first examples section of this site for the syntax on specifying a particular controller and action for a link_to helper here.
Just check the corresponding action in the controller.
If there is a render or redirect_to just delete it
it works for me (Rails 4)
How can I limit a user to only to being able to post once or twice per day on a particular users's wall? I primarily want to do it in order to limit spam. My code for the wall, models, view, and controllers are below. I don't really know how to go about it as I'm new to rails but I know there is something time.now. I'm not exactly sure how to implement such a feature.
Class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#first_name = #user.first_name
#last_name = #user.last_name
#wallpost = WallPost.new(params[:wall_post])
#showwallposts = #user.received_wallposts
end
def create
#wallpost = WallPost.create(params[:wall_post])
end
models
class WallPost < ActiveRecord::Base
attr_accessible :content, :receiver_id, :sender_id
belongs_to :receiver, :class_name => "User", :foreign_key => "receiver_id"
belongs_to :sender, :class_name => "User", :foreign_key => "sender_id"
end
class User < ActiveRecord::Base
has_many :sent_wallposts, :class_name => 'WallPost', :foreign_key => 'sender_id'
has_many :received_wallposts, :class_name =>'WallPost', :foreign_key => 'receiver_id'
in the view
<%= form_for(#wallpost, :url => {:action => 'create'}) do |f| %>
<%= f.hidden_field :receiver_id, :value => #user.id %>
<%= f.hidden_field :sender_id, :value => current_user.id %>
<%= f.text_area :content, :class => 'inputbox' %>
<%= f.submit 'Post', class: 'right btn' %>
<% end %>
You could create a custom validator which assures maximum DAILY_LIMIT posts have been created on that person's wall that day by that user:
class SpamValidator < ActiveModel::Validator
DAILY_LIMIT = 2
def validate(record)
if similar_posts_today(record).count >= DAILY_LIMIT
record.errors[:spam_limit] << 'Too many posts today!'
end
end
def similar_posts_today(record)
WallPost.where(receiver: record.receiver, sender: record.sender)
.where("DATE(created_at) = DATE(:now)", now: Time.now)
end
end
Then add that validation to your WallPost model:
validates_with SpamValidator
Then it will fail with a validation error when trying to create a wall post beyond the limit set in the constant. You need to handle this case in the create action in your controller. A simple (but not optimal in terms of user experience) way of handling this is:
def create
#wallpost = WallPost.new(params[:wall_post])
flash[:error] = "You've reached the daily posting limit on that wall." unless #wallpost.save
redirect_to user_path(#wallpost.receiver)
end
With that, it'll try to save the new wall post, if it is unable to, it'll set flash[:error] to the error message above. You'd need to show this on your show.html.erb page with <%= flash[:error] if flash[:error] %>.
I'm trying to set up a polymorphic association for photo uploads which are processed using Carrierwave. I'm using Simple Form to build my forms. I feel like the association is correct so I'm wondering if my problem is just something with the form or controller.
Here are my associations:
property.rb:
class Property < ActiveRecord::Base
attr_accessible :image
...
has_many :image, :as => :attachable
...
end
unit.rb
class Unit < ActiveRecord::Base
attr_accessible :image
...
has_many :image, :as => :attachable
end
image.rb
class Image < ActiveRecord::Base
belongs_to :attachable, :polymorphic => true
mount_uploader :image, PhotoUploader
end
properties_controller.rb:
def edit
#property = Property.find params[:id]
#property.image.build if #property.image.empty?
end
def update
#property = Property.find params[:id]
if #property.update_attributes params[:property]
redirect_to admin_properties_path, :notice => 'The property has been successfully updated.'
else
render "edit"
end
end
Snippet from properties/_form.html.erb
<%= f.input :image, :label => 'Image:', :as => :file %>
Here is the error I get when submitting with an image attached:
undefined method `each' for #<ActionDispatch::Http::UploadedFile:0x00000102291bb8>
And here are the params:
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"lvB7EMdc7juip3gBZD3XhCLyiv1Vwq/hIFdb6f1MtIA=",
"property"=>{"name"=>"Delaware Woods",
"address"=>"",
"city"=>"",
"state"=>"",
"postal_code"=>"",
"description"=>"2 bedroom with large kitchen. Garage available",
"incentives"=>"",
"active"=>"1",
"feature_ids"=>[""],
"user_ids"=>[""],
"image"=>#<ActionDispatch::Http::UploadedFile:0x00000102291bb8 #original_filename="wallpaper-4331.jpg",
#content_type="image/jpeg",
#headers="Content-Disposition: form-data; name=\"property[image]\"; filename=\"wallpaper-4331.jpg\"\r\nContent-Type: image/jpeg\r\n",
#tempfile=#<File:/tmp/RackMultipart20120608-3102-13f3pyv>>},
"commit"=>"Update Property",
"id"=>"18"}
I'm looking everywhere for help on polymorphic associations and am getting nowhere. I've seen simple examples that look pretty straight forward. One thing I've noticed is that it seems like in a lot of the examples the has_many association in my case should be images and not image. However when I do that I get an error:
Can't mass-assign protected attributes: image
I've tried updating my form to use fields_for as I've seen in other blogs like so:
<%= f.input :image, :label => "Photo", :as => :file %>
<% f.simple_fields_for :images do |images_form| %>
<%= images_form.input :id, :as => :hidden %>
<%= images_form.input :attachable_id, :as => :hidden %>
<%= images_form.input :attachable_type, :as => :hidden %>
<%= images_form.input :image, :as => :file %>
<% end %>
All I know is I'm having a heck of a time getting this to work. I'm pretty new to Rails so even debugging it is difficult. It doesn't help that the debugger doesn't really work in 3.2 :(
Since your models have_many :images (it should be :images, not :image), you'll want to use nested_forms in your views. You should set up accepts_nested_attributes_for :images on the unit and property models and change the attr_accessible from :image to :image_attributes.
Check out http://railscasts.com/episodes/196-nested-model-form-part-1 for a good guide on getting going with it.
I have a form attached to profiles where short comments can be submitted. I want to capture the author's name though so I can display it in a tooltip when hovering over the comment's body.
In my create method in the controller I have:
def create
#comment = Comment.new(params[:comment])
#comment.save!
redirect_to profile_path(#comment.profile)
end
Inside my migration:
t.timestamps
t.integer :profile_id
t.string :author_id
t.string :body
Profile model:
belongs_to :user
accepts_nested_attributes_for :user
has_many :comments
Comment model:
belongs_to :profile
ProfilesController:
def show
#user = User.find(params[:id])
#profile = user.profile
#superlative = #profile.superlatives.new
end
And my form:
<%= form_for #comment do |f| %>
<%= f.hidden_field :profile_id, :value => #profile.id %>
<%= f.hidden_field :author_id, :value => "#{current_user.profile.first_name} #{current_user.profile.last_name}" %>
<%= f.text_field :body %>
<%= f.submit 'Add new' %>
<% end %>
I was thinking of linking the :author_id to current_user.profile.id and using that association to display :first_name and :last_name which are attributes of the profile. Or is there a simpler, better way?
UPDATE: I got it to display the name though I'm still curious if there's a better way.
Your solution looks fine, but I'd store the User (or whatever class current_user returns) instead of the Profile:
In app/models/comment.rb:
class Comment < ActiveRecord::Base
belongs_to :profile
belongs_to :author, :class_name => "User", :foreign_key => "author_id"
... rest of the code ...
end
You then change your migration to:
t.integer :author_id
and your controller method to:
def create
#comment = Comment.new(params[:comment].merge(:author_id => current_user.id))
#comment.save!
redirect_to profile_path(#comment.profile)
end
In your view (I used the title attribute do create a tooltip, but feel free to use whatever method you like):
<div class="comment" title="<%= #comment.author.profile.first_name %> <%= #comment.author.profile.last_name %>">
<%= #comment.body %>
</div>
I would suggest something like this:
In your routes.rb create a nested resource for comments
resources :users do
resources :comments
end
In your User model
class User
has_many :comments
end
In your Comment model
class Comment
belongs_to :user
end
In your CommentsController in the new and create methods
#comment = User.find(params[:user_id]).comments.new(params[:comment])
So the comment automagically gets created as belonging to that User and you don't have to pass anything around.
Then, in your Comment view, you could just call its owners name
#comment.user.first_name