hey everyone so I'm working on a small blog and there is a new section a want to add. An "editor's choice" section so basically i want to add a small div that contains 3 randomly pick posts from the blog. The problem is I do not know how to show only three randomely select titles from all the posts. I tried #posts.sample(3) and that shows the entire record of the Post. I just want to show the title only.
I want to show the editors choice on the posts index view
Schema
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "content"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "user_id"
t.string "nickname"
end
Posts_controller
class PostsController < ApplicationController
before_action :current, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.all
end
def show
end
def new
#post = Post.new
end
def create
#post = Post.new(posts_params)
#post.user = current_user
if #post.save
redirect_to posts_path
else
render :new
end
end
def edit
end
def update
#post.user = current_user
#post.update(posts_params)
#post.save
redirect_to posts_path
end
def destroy
if #post.destroy
redirect_to posts_path
end
end
private
def posts_params
params.require(:post).permit(:title, :content, :user_id, :image, :nickname)
end
def current
#post = Post.find_by(id: params[:id])
end
end
post_index.html.erb
<%= render "layouts/blog_header" %>
<% #posts.each do |post| %>
<div class="posts">
<div>
<% unless !post.image.attached? %>
<%= image_tag post.image, class: "post-index-image" %><br>
<% end %>
</div>
<p class="post-index-title"><%= link_to post.title, post_path(post.id), class: "post-index-title" %></p>
<p>Published by: <strong><%= post.user.nickname %></strong></p>
</div>
<% end %>
<%= #posts.sample(3) %>
Thanks!
I would start with something like this when you are using PostgreSQL:
#posts.order('RANDOM()').limit(3)
or when you are on MySQL:
#posts.order('RAND()').limit(3)
I think it should do what you want:
#posts.sample(3).pluck(:title)
I'd go with
#posts.pluck(:title).sample(3)
More efficient than
#posts.sample(3).pluck(:title)
Related
Thank you for taking the time to review this question.
I have a nested resource called templates, which belong to categories. I have the template create, edit and delete actions displayed in the Category Show page. I am able to create with no issue, however, when attempting to edit or delete the same template gets retrieved by its ID (usually the first template created under a category).
Code
config/routes.rb
resources :categories do
resources :templates
app/models/template.rb
class Template < ApplicationRecord
belongs_to :category
validates :title, presence: true
validates :content, presence: true
end
app/models/category.rb
class Category < ApplicationRecord
belongs_to :user
has_many :templates, dependent: :destroy
validates :name, presence: true
end
db/schema.rb
create_table "categories", force: :cascade do |t|
t.string "name"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_categories_on_user_id"
end
create_table "templates", force: :cascade do |t|
t.integer "user_id"
t.integer "category_id"
t.string "title"
t.text "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["category_id"], name: "index_templates_on_category_id"
t.index ["user_id"], name: "index_templates_on_user_id"
end
app/views/categories/show.html.erb
<% #templates.each do |template| %>
<div class= "template-grid">
<div class= "template-index-card">
<h1><%= template.title%></h1>
<p><%= template.content %></p>
<div class= "template-options">
<%= link_to image_tag("edit.png", class: "icon"), edit_category_template_path([#category, #template])%>
<%= link_to image_tag("bin.png", class: "icon"), category_template_path([#category, #template]), method: :delete,
data: { confirm: 'Are you sure?' }%>
app/views/templates/edit.html.erb
<%= simple_form_for([#category, #template]) do |f| %>
<div class="form-inputs">
<%= f.input :title %>
<%= f.input :content %>
</div>
<div class= "form-btn-flex">
<%= f.button :submit, "Update Template", class:"btn-mdpm-forms"%>
<% end %>
app/controllers/templates_controller.rb
class TemplatesController < ApplicationController
def new
#template = Template.new
end
def create
#template = Template.new(template_params)
#template.user_id = current_user.id
#template.category = Category.find(params[:category_id])
if #template.save
redirect_to category_path(#template.category_id)
else
render :show
end
end
def index
#templates = Template.all
end
def show
#template = Template.find(params[:id])
end
def edit
#category = Category.find(params[:category_id])
#template = #category.templates.find_by(params[:id])
end
def update
#category = Category.find_by(params[:category_id])
#template = #category.templates.find_by(params[:id])
if #template.update(template_params)
redirect_to category_path(#category)
else
render :edit
end
end
def destroy
#template = Template.find_by(params[:id])
#template.destroy
redirect_to category_path(#template.category_id)
end
private
def template_params
params.require(:template).permit(:title, :content)
end
end
app/controllers/categories_controller.rb
class CategoriesController < ApplicationController
before_action :set_category, only: [:edit, :update]
def new
#category = Category.new
end
def create
#category = Category.new(category_params)
#category.user = current_user
if #category.save
redirect_to categories_path
else
render :index
end
end
def index
#category = Category.new
#categories = Category.all
end
def show
#template = Template.new
#category = Category.find(params[:id])
#templates = #category.templates
end
def edit
#category = Category.find(params[:id])
end
def update
if #category.update(category_params)
redirect_to category_path(#category)
else
render :edit
end
end
def destroy
#category = Category.find(params[:id])
#category.destroy
redirect_to categories_path
end
private
def category_params
params.require(:category).permit(:name)
end
def set_category
#category = Category.find(params[:id])
end
end
Routes
category_templates GET /categories/:category_id/templates(.:format) templates#index
POST /categories/:category_id/templates(.:format) templates#create
new_category_template GET /categories/:category_id/templates/new(.:format) templates#new
edit_category_template GET /categories/:category_id/templates/:id/edit(.:format) templates#edit
category_template GET /categories/:category_id/templates/:id(.:format) templates#show
PATCH /categories/:category_id/templates/:id(.:format) templates#update
PUT /categories/:category_id/templates/:id(.:format) templates#update
DELETE /categories/:category_id/templates/:id(.:format) templates#destroy
categories GET /categories(.:format) categories#index
POST /categories(.:format) categories#create
new_category GET /categories/new(.:format) categories#new
edit_category GET /categories/:id/edit(.:format) categories#edit
category GET /categories/:id(.:format) categories#show
PATCH /categories/:id(.:format) categories#update
PUT /categories/:id(.:format) categories#update
DELETE /categories/:id(.:format) categories#destroy
Thanks!
The problem ended up being a matter of too many variables named the same. In order to fix the issue I had to make the following changes:
1 - On app/views/categories/show.html.erb I removed the # form template since I was inside an iteration, I also passed the params not as an array as suggested.
<% #templates.each do |template| %>
<div class= "template-grid">
<div class= "template-index-card">
<h1><%= template.title%></h1>
<p><%= template.content %></p>
<div class= "template-options">
<%= link_to image_tag("edit.png", class: "icon"), edit_category_template_path(#category, template)%>
<%= link_to image_tag("bin.png", class: "icon"), category_template_path(#category, template), method: :delete,
data: { confirm: 'Are you sure?' }%>
I updated the name of the #template variable to #templately on the show method of app/controllers/categories_controller.rb so that I could use #template to pass the id on the edit method on the template_controller.
how about passing the params, not as an array?
<%= link_to image_tag("edit.png", class: "icon"), edit_category_template_path(category_id: #category.id, id: #template.id)%>
<%= link_to image_tag("bin.png", class: "icon"), category_template_path(category_id: #category.id, id: #template.id), method: :delete,
...
How can I call comments + user information that is specified to the specific post the comment was created under. For example:
/articles/8
new comment created with user_id = 3
Page will show Username + comment + created_at
This is my current code:
Post Show Page
<%= #post.title %>
<%= render '/comments/form' %>
<% #post.user.comments.reverse.each do |comment| %>
<li>
<%= comment.user.email %>
<%= comment.comment %>
</li>
<% end %>
I grab user information associated with the comment but the problem is, it's listing all the comments. How do I make only comments with article_id of 8 for example appear.
Post Controller
def create
#post = Post.new(post_params)
#post.user = current_user
if #post.save!
flash[:notice] = "Successfully created..."
redirect_to posts_path
else
flash[:danger] = "failed to add a post"
render 'new'
end
end
def show
#comment = Comment.new
#comments = Comment.find(params[:id])
end
Comment Controller
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(comment_params)
#comment.user = current_user
if #comment.save
flash[:notice] = "Successfully created..."
redirect_to post_path(#post)
else
flash[:alert] = "failed"
redirect_to root_path
end
end
Routes
resources :sessions, only: [:new, :create, :destroy]
resources :users
resources :posts do
resources :comments
end
Schema of the comments
create_table "comments", force: :cascade do |t|
t.text "comment"
t.integer "user_id"
t.integer "post_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
I am assuming that your model looks like
class Comments < ApplicationRecord
belongs_to :user
belongs_to :post
end
class User < ApplicationRecord
has_many :posts
has_many :comments
end
class Post < ApplicationRecord
belongs_to :user
has_many :comments
end
We want to get all the comments for a post so we we can do something like this
# Note that I took the user from this line
<% #post.comments.reverse.each do |comment| %>
<li>
<%= comment.user.email %>
<%= comment.comment %>
</li>
<% end %>
I hope that this should work.
Alright guys,
I don't know why my new/create actions are giving me trouble right now, but I am getting the following error. Any ideas as to why? Thank you in advance.
ActionController::ParameterMissing in ArtistYoutubeVideosController#create
param is missing or the value is empty: youtube_vid
And it highlights these lines of code:
def create
#youtube_vid = ArtistYoutubeVideo.new(youtube_vid_params)
if #youtube_vid.save
redirect_to artist_youtube_videos_path
else
render :new
end
end
def youtube_vid_params
params.require(:youtube_vid).permit(:id, :video_name, :video_url)
end
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"HGnaAPOrw8Fbz7/dR12GXRoo6ZWByCbqN5L15C0D5yxBlpLy0afRkVaJ1peJkt1pB+tqZaytgJPJTNPoEl54yg==",
"artist_youtube_video"=>{"video_name"=>"test 11",
"video_url"=>"test 11"},
"commit"=>"Submit"}
ArtistYoutubeVideosController.rb
class ArtistYoutubeVideosController < ApplicationController
def index
#youtube_vids = ArtistYoutubeVideo.all
end
def new
#youtube_vid = ArtistYoutubeVideo.new
end
def create
#youtube_vid = ArtistYoutubeVideo.new(youtube_vid_params)
if #youtube_vid.save
redirect_to artist_youtube_videos_path
else
render :new
end
end
def youtube_vid_params
params.require(:youtube_vid).permit(:id, :video_name, :video_url)
end
end
artist_youtube_videos/new.html.erb
<h1>New Youtube Vids</h1>
<%= form_for(#youtube_vid) do |f| %>
<%= f.label :video_name %>
<%= f.text_field :video_name %>
<%= f.label :video_url %>
<%= f.text_field :video_url %>
<%= f.submit "Submit" %>
<% end %>
schema.rb
create_table "artist_youtube_videos", force: :cascade do |t|
t.string "video_name"
t.text "video_url"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
routes.rb
resources :artist_youtube_videos
As per params you've posted, change
def youtube_vid_params
params.require(:youtube_vid).permit(:id, :video_name, :video_url)
end
to
def youtube_vid_params
params.require(:artist_youtube_video).permit(:id, :video_name, :video_url)
end
and you'll be good.
building my first blog, head is spinning.
I am trying to show comments in my dashboard view. I am able to pull in the comments and the ID but what I would really like to do is also put the title of the post the comment lives and link to it. From my very amateur understanding I think I am not making the connection from comments to post.
Here is what I got...
Post model has_many :comments
Comments model belongs_to :posts
routes
resources: posts do
resources: comments
end
Dashboard Controller:
class DashboardController < ApplicationController
before_filter :authorize, only: [:index]
def index
#posts = Post.all
#comments = Comment.all
end
end
Comments Controller:
class CommentsController < ApplicationController
before_filter :authorize, only: [:destroy, :show]
def create
#post = Post.find(params[:post_id])
#comment =
#post.comments.create(comments_params)
redirect_to post_path(#post)
end
def destroy
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.destroy
redirect_to post_path(#post)
end
private
def comments_params
params.require(:comment).permit(:commenter, :body)
end
end
Posts Controller:
class PostsController < ApplicationController
before_filter :authorize, only: [:edit, :update, :destroy, :create, :new]
def index
#posts = Post.where(:state => "published").order("created_at DESC")
end
def new
#post = Post.new
end
def show
#post = Post.find(params[:id])
redirect_to_good_slug(#post) and return if bad_slug?(#post)
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to dashboard_path
else
render 'new'
end
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
if #post.update(params[:post].permit(post_params))
redirect_to dashboard_path
else
render 'edit'
end
end
def destroy
#post = Post.find(params[:id])
#post.destroy
redirect_to dashboard_path
end
private
def post_params
params.require(:post).permit(:title, :text, :author, :short, :photo, :state)
end
end
Dashboard View:
</div>
<div class="fluid dash">
<div class="gridContainer clearfix">
<div class="fluid dash_post_list">
<h3>Manage Posts</h3>
<% #posts.each do |post| %>
<div class="fluid list-items">
<div class="fluid list_each">
| <%= post.id %> | <%= link_to post.title, post %>, <%= post.created_at.strftime('%b, %d') %> - <%= post.state %>
</div>
<div class="fluid crud">
<i class="fa fa-pencil-square-o"></i><%= link_to 'Edit', edit_post_path(post) %>
<i class="fa fa-times-circle"></i><%= link_to 'Delete', post_path(post),
method: :delete, data: { confirm: 'Are you sure?' } %>
</div>
</div>
<% end %>
</div>
<div class="fluid dash_right">
<div class="fluid create_new">
<h3>Create New</h3>
<%= link_to 'New Post', new_post_path %>
</div>
<div class="fluid alerts">
<h3>Alerts!</h3>
<% #comments.each do |comment| %>
<%= comment.post_id %>
<% end %>
</div>
</div>
</div>
</div>
DB Schema
create_table "comments", force: true do |t|
t.string "commenter"
t.text "body"
t.integer "post_id"
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "flag", default: false
end
create_table "posts", force: true do |t|
t.string "title"
t.text "text"
t.datetime "created_at"
t.datetime "updated_at"
t.text "short"
t.text "author"
t.string "photo_file_name"
t.string "photo_content_type"
t.integer "photo_file_size"
t.datetime "photo_updated_at"
t.string "state"
end
The end goal is, when a user makes a new comment, add it to alerts in the dashboard where I can then take a link from the dashboard to the post and then approve or delete it.
Thanks you for any help you can give me.
So from you question, My understanding is that you cannot create a link to the post?
Forgetting ajax for now. This is how you like it to the post show page.
Dashboard:
-#comments.each do |comment|
.comment
=link_to comment.body, comment.post
and in the post show page
-#comment.each do |comment|
.comment
=link_to 'Approve', approve_comment_path(comment)
=link_to 'Delete', comment_path(comment), method: :delete
You will need a custom action to set it to approve or you can reuse the update action.
So I have this form in my books view, which shows a select box to choose if a boolean value is either true or false.
But when I submit it, it does not change the boolean value to true, if I select so.
This is my books scheme basicly:
create_table "books", force: true do |t|
t.string "name"
t.integer "user_id"
t.boolean "oppetool", default: false
t.datetime "created_at"
t.datetime "updated_at"
t.integer "count", default: 0
end
Why is it not changing the boolean value for my entry?
My view:
<% provide(:title, "Submit a book") %>
<b align="center">Enter the name of a book you want to add into the database and then press 'Submit!'</b>
<%= form_for(#book) do |f| %>
<div class="forms">
<%= f.text_field :name, placeholder: "Type what you want to say...", autofocus: true %>
<%= f.check_box(:oppetool, {}, "True", "False") %>
<%= f.submit 'Submit!' %>
</div>
<% end %>
Books controller:
class BooksController < ApplicationController
before_action :signed_in_user, only: [:index,:edit,:update, :destroy]
before_action :admin_user, only: :destroy
before_action :set_book, only: [:show, :edit, :update, :destroy]
def index
#books = Book.all
end
def show
#book = Book.find(params[:id])
end
def new
#book = current_user.books.build
end
def create
#book = current_user.books.build(book_params)
if #book.save
flash[:success] = "Book listed!"
redirect_to books_path
else
flash[:success] = "Did you leave a field empty? All fields must be filled before we can accept the review!"
render new_book_path
end
end
def edit
end
def update
end
def destroy
end
# Private section
private
def book_params
params.require(:book).permit(:name, :user_id)
end
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
# Redirecting not logged in user etc.
def signed_in_user
unless signed_in?
store_location
redirect_to '/sessions/new', notice: "Please sign in!"
end
end
end
First of all, update book_params to allow oppetool
params.require(:book).permit :name, :user_id, :oppetool
Then simply use
<%= f.check_box :oppetool %>
The default setting use "0" for false and "1" for true.
You haven't included :oppetools in your list of permitted parameters (book_params).
What prevents the value from changing is this line in your controller logic:
params.require(:book).permit(:name, :user_id)
You essentially block out :oppetool from being changed here. Change this line to
params.require(:book).permit(:name, :oppetool).
I would also remove :user_id here to avoid people mass-assigning this value, which is probably what you want.
By the way, why do you set the two checkbox values yourself, instead of leaving them blank, like this:
<%= f.check_box(:oppetool) %> ?
If you used this, Rails should automagically convert the default values "0" and "1" to the corresponding boolean value. I'm not sure if that works for "True" and "False" properly, too, that's why I'm asking.