What is the proper "RESTFUL" way to list all posts - ruby-on-rails

I am trying to figure out the proper restful way of displaying all posts from all users.
I have an application with a user and post resource. The post resource is nested in the users. Now I am trying to sort of display a feed of all posts and with the name of the user who posted them.
I cant quite figure out where this feed should be placed. And in view file, how to get post user names.

in controller:
#posts = Post.all(:include => "user")
in view:
<% #posts.each do |post| %>
...
some html here
...
<%= post.user.name %>
<% end %>
Pay attention to "include" word. It means that users information will be got with posts with 1 query to Database.
To better understand it you can read this

You can create a route for displaying all posts by:
routes.rb
get "posts" => "posts#index"
This will create a route http://yourdomain.com/posts that will show all posts. Then make sure you have an action for index to show all of the posts.
posts_controller.rb
class PostsController < ApplicationController
def index
#posts = Post.all(:include => "user")
end
end
Make sure your model associations are set up properly.
user.rb
has_many :posts
post.rb
belongs_to :user
# This assumes you have a column on your table for user_id which I assume you do since you mentioned your nested resource already.
You view would simply show the user's name associated with each post.
views/posts/index.rb
<% #posts.each do |post| %>
post.user.name
<% end %>

Related

Rails Need help to capture form field in model from product view

I need to capture a field added by a user in a form_for, inside the product show page.
My product.rb model as follows:
belongs_to :user
has_many :complaints
My complaint.rb model as follows:
belongs_to :product
belongs_to :user
My user.rb model as follows:
has_many :products
My product controller is a basic controller with all the new, create, edit, update actions and all the routes are good.
User looks at the product show page like this, and it's all good
http://localhost:3000/products/1
My goal is to create a complaint from the product show page, when user views the specific product. So I have created a complaints_controller.rb to capture all the details of the product, and create a complaint. I have an issue with capturing the complaint_number which is a field inside the complaints table.
Here is my form inside the product show page
<%= form_for([#product, #product.complaints.new]) do |f| %>
<%= f.number_field :complaint_number, placeholder: "Enter complaint number you were given" %>
<%= f.submit 'Complaint' %>
<% end %>
Here is my complaints_controller.rb
Goal is to capture the complaint_number fields and run the make_complaint method to create a complaint and populate rest of the fields in the newly created row of the complains table.
class ComplaintsController < ApplicationController
before_action :authenticate_user!
def create
# Will Get product_id from the action in the form in product show page.
product = Product.find(params[:product_id])
# This complaint_number does not seem to work
complaint_number = product.complaints.find_by(complaint_number: params[:complaint_number])
# Now I want to run a make_complaint method and pass the product and the complaint number. This fails, I can't capture the complaint_number in the form from user input.
make_complaint(product, complaint_number)
redirect_to request.referrer
end
private
def make_complaint(product, complaint_number)
complaint = product.complaints.new
complaint.title = product.title
complaint.owner_name = product.user.name
complaint.owner_id = product.user.id
# Note: complaint_number and current_complaint are a fields in the Orders table
# Note:
complaint.current_complaint = complaint_number
if complaint.save
flash[:notice] = "Your complaint has been sent!"
else
flash[:alert] = complaint.errors.full_messages
end
end
end
For routes I have added resources :complaint, only: [:create] inside the resources of products to get products/:id/complaints
My routes.rb is like this
Rails.application.routes.draw do
get 'products/new'
get 'products/create'
get 'products/edit'
get 'products/update'
get 'products/show'
root 'pages#home'
get '/users/:id', to: 'users#show'
post '/users/edit', to: 'users#update'
resources :products do
member do
delete :remove_image
post :upload_image
end
resources :complaint, only: [:create]
end
devise_for :users, path: '', path_names: { sign_in: 'login', sign_up: 'register', sign_out: 'logout', edit: 'profile' }
Your form has complaint_quantity:
<%= form_for([#product, #product.complaints.new]) do |f| %>
<%= f.number_field :complaint_quantity, placeholder: "Enter complaint number you were given" %>
<%= f.submit 'Complaint' %>
<% end %>
Your controller has complaint_number:
complaint_number = product.complaints.find_by(complaint_number: params[:complaint_number])
If you check your params from the server log, I bet you'll see the value you are looking for is coming across as complaint_quantity and not complaint_number.
UPDATE
With the form misspelling corrected, the error persists, so let's check into more areas:
complaint_number = product.complaints.find_by(complaint_number: params[:complaint_number])
So, break that down:
1. What does params actually include?
Is :complaint_number being submitted from the form?
If not, the form still has an error somewhere.
2. Does product.complaints actually include a complaint that could be matched by complaint_number?
I don't know your data structure well enough to tell, but it looks to me like you might actually want to do:
Complaint.find_by(complaint_number: params[:complaint_number])
instead of:
products.complaints.find_by(complaint_number: params[:complaint_number])
UPDATE #2
You know the problem is with your params.
I'm confident you aren't accessing your params correctly since you are using a nested form:
form_for([#product, #product.complaints.new])
Should mean your params are structured like { product: { complaint: { complaint_number: 1234 }}}
So params[: complaint_number] is nil because it should really be something like params[:product][:complaint][:complaint_number]
Please look at your server log in your terminal right after you submit the form to see the structure of your params. Or insert a debugger in the controller action and see what params returns.
ALSO, Instead of accessing params directly, you should whitelist params as a private method in your controller.
Something along these lines:
private
def product_complaint_params
params.require(:product).permit(:id, complaint_params: [ :complaint_number ])
end
See this: https://api.rubyonrails.org/classes/ActionController/StrongParameters.html

How could I add to a table from from a different model HTML page?

I'm new to rails. I have a table TeamMemberships that has a foreign key to Students and a foreign key to Teams. I want to be able to have a link in the show.html.erb page for a specific team that redirects to a form that lets me add a row to TeamMemberships in which the Team foreign key is the team whose show.html.erb page the link was clicked on and the Student foreign key would be determined by the form. Is this possible?
Thanks!
Add a new resources in your routes.rb file like so:
Rails.application.routes.draw do
resources :teams do
resources :team_memberships
end
end
Which will create the CRUD routes:
team_team_memberships GET /teams/:team_id/team_memberships(.:format) team_memberships#index
POST /teams/:team_id/team_memberships(.:format) team_memberships#create
new_team_team_membership GET /teams/:team_id/team_memberships/new(.:format) team_memberships#new
edit_team_team_membership GET /teams/:team_id/team_memberships/:id/edit(.:format) team_memberships#edit
team_team_membership GET /teams/:team_id/team_memberships/:id(.:format) team_memberships#show
PATCH /teams/:team_id/team_memberships/:id(.:format) team_memberships#update
PUT /teams/:team_id/team_memberships/:id(.:format) team_memberships#update
DELETE /teams/:team_id/team_memberships/:id(.:format) team_memberships#destroy
What is interesting you here is the new_team_team_membership GET /teams/:team_id/team_memberships/new(.:format) that you can call using the named route new_team_team_membership.
You will be able to pass the team ID for which you'd like to create the TeamMembership in the route with new_team_team_membership_path(#team.id).\
Regarding the student_id you will pass it in the HTTP POST request body.
Here is how to create the link from the team show page to the TeamMembership form:
<%= link_to 'Add a student', new_team_team_membership_path(#team.id) %>
You will have to create the TeamMembershipsController and the new action. The action should initialise the #new_team_membership variable that will be used by the form and load the student list like so:
class TeamMembershipsController < ApplicationController
def new
#new_team_membership = TeamMembership.new(team_id: params[:team_id])
#students = Student.all
end
end
Then you have to create the app/views/team_memberships/ folder and add the new.html.erb file with the following form:
<%= form_for #new_team_membership do |f| %>
<%= f.select :student_id, options_for_select(#students.collect{ |student| [student.name, student.id]) %>
<%= f.submit %>
<% end %>
Then in your TeamMembershipsController controller, you have to define the create action that will receive in parameter the team_id, and from the form the selected student_id. You will then be able to create the TeamMembership instance.
Update
Regarding the create action of the TeamMembershipsController controller, here is how it should be done:
class TeamMembershipsController < ApplicationController
def new
# ...
end
def create
# The form should have embedded all the params within a key with the model's name
# like `:team_membership`.
student = Student.find(params[:team_membership][:student_id])
#team_membership = TeamMembership.new(
team_id: params[:team_id],
student: student
)
if #team_membership.save
redirect_to :team_path(params[:team_id])
else
# Reload again the student as we will show errors.
# The student dropdown would be empty.
#students = Student.all
# Render again the new form
render :new
end
end
end

How to display all posts with all its comments - Ruby on Rails

I'm new to rails and don't know how to achieve this in rails. It might be a really stupid question. But it was not covered in the RoR Codecademy course I did and could not fint a answer elsewhere.
So I have two tables, posts and comments that have an one-to-many relationship. One post has many comments.
I want to display all post with all its comments underneath. What would be the correct way to do this?
There are two ways to do this:
First: you can do like this way in your post controller action (suppose :index) do:
def index
#posts = Post.all
end
And in your index.html.erb
<% #posts.each do |post|%>
# Your post attribute like name etc
<% post.comments.each do |comment|%>
# Your post attribute like name etc
<% end %>
<% end %>
Second: in your post controller action do:
def index
#posts = Post.all.includes(:comments)
end
And in your index.html.erb
<% #posts.each do |post|%>
# Your post attribute like name etc
<% post.comments.each do |comment|%>
# Your post attribute like name etc
<% end %>
<% end %>
Difference in above two ways is that in first one there is always a data base call when you do "post.comments" but in second there is only two data base call i.e. "Post.all.includes(:comments)", no data base call at view part, so it is up to you which way you want to use.
If a Post has_many comments then:
post = Post.find(1)
post.comments.each do |comment|
# do something with each comment here
end

Ruby on Rails 4, How to Display User in Another page

I am new to Ruby on rails. I've created basic demo apps by tutorial learning by examples.
Application have three model User,Village and article
Village has many users, Village has many articles, user and article belongs to village
I work , migration work fine
when iam in http://0.0.0.0:3000/villages/1 , i display all user that belong to village 1
My question is how display in all user in village one this url http://0.0.0.0:3000/villages/1/users
To do that you need to add the url to the routes.rb file under the config folder.
Add line like below
resources :villages do
member do
get '/user', to: 'villages#show'
end
end
I am assuming that your villages show action is the one that has all the user details displayed.
routes.rb
resources :villages do
member do
get :users, :articles
end
end
In villages_controller
def users
#village = Village.find(params[:id])
#values = #village.users.paginate(page: params[:page])
render 'show_data'
end
def articles
#village = Village.find(params[:id])
#values = #village.articles.paginate(page: params[:page])
render 'show_data'
end
In show_data.html.erb
<% if #values.any? %>
<% #values.each do |value| %>
<%= value.name %>
<% end %>
<%end%>
<%= will_paginate %>

rails post path issue

I've an issue with the paths in the views and I don't know how to solve it.
I've "categories" that has_many "posts" and "posts" that belongs_to "categories".
1.- I want to show on home page the truncate last post of an specific category (the ID number "1"). Then I want that post to link to the show post path but I get this error:
"Unknow Action
The action 'index' could not be found for PostsController"
I think I've my paths wrong because I don't need the index view because I'm only going to show that specific post. So, I think that category_posts_path(#last_post) is not the right path (I don't know where to look for more info about making the route path in the views...). Actually, the browser is showing me that is looking for the "2" category when it is a post of the "1" category...? What am I doing wrong?
This is the browser route:
http://localhost:3000/en/categories/2/posts
This is my views/categories/home.html.erb file:
<div class="post_details">
<h2><%= #last_post.title %></h2>
<%= image_tag #last_post.image(:header), class: "post_image" %>
<p><%= truncate #last_post.body, length: 100 %></p>
<p class="button"><%= link_to "READ MORE", category_posts_path(#last_post) %></p>
</div>
2.- I have another path problem in the views/categories/show.html.erb file. I have a loop to show all the post of one specific category, but when I link in some post (to show it) there is the "index" error again:
"Unknow action
The action 'index' could not be found for PostsController"
This is the browser route:
http://localhost:3000/en/categories/1/posts
This is the views/categories/show.html.erb file:
<div class="post_details">
<h2><%= link_to post.title, category_posts_path(post) %></h2>
<%= image_tag post.image(:header), class: "post_image" %>
<p><%= post.body %></p>
</div>
This is the categories_controller.rb file:
class CategoriesController < ApplicationController
before_action :get_categories
def index
end
def show
#category = Category.find(params[:id])
end
def home
if params[:set_locale]
redirect_to root_url(locale: params[:set_locale])
else
#category = Category.find_by_id(1)
#last_post = #category.posts.order("created_at desc").first
end
end
def get_categories
#categories = Category.all.order("rank asc, name asc")
end
end
This is my posts_controller.rb file:
class PostsController < ApplicationController
def show
#category = Category.find(params[:category_id])
#post = #category.posts.find(params[:id])
end
end
This is my route.rb file:
scope '(:locale)' do
resources :categories do
resources :posts
end
resources :contacts
root 'categories#home'
get "/contact" => "contacts#new"
# static pages
get "/investment" => "contents#investment"
get "/partner-with-us" => "contents#partner", as: "partner"
get "/our-companies" => "contents#companies", as: "companies"
get "/site-map" => "contents#sitemap", as: "sitemap"
get "/terms-and-conditions" => "contents#terms", as: "terms"
get "/privacy" => "contents#privacy"
end
When you are nesting routes you should always consider what is the parent and whats a child in given route. Since your paths don't know anything about your associations you have to explicitly define every object in the nesting.
I.e. since you nested posts in categories linking to last post in given category would look like this:
category_post_path(#category, #last_post)
(I think you have also a typo there - category_posts_paths - which links to posts index index - hence the error. Use category_post_path. instead, and give it both parent category and the post.
You can run rake routes to see exact information on paths (or go to http://localhost:3000/rails/info/routes )

Resources