How do I display several posts in related "weeks"
I would like to structure my blog so that I can assign posts I have created with Trix and Shrine to weeks.
I want to have 12 teaserboxes on my index page which can then be clicked and if I click on week 1, for example, only the posts that are assigned to week 1 are displayed.
What's the smartest way to go? Should I make an extra week model? And can I somehow make a sort of assignment while creating the post that this post is a post for week 1? Are there any instructions or tips on how to do this? I'm totally overwhelmed with it right now. Currently all my posts are listed under /posts.
Hi Sebastian,
Depending on how much control you really need, the simplest would probably be to just add an integer week
column to your Post
model for you to enter the week number when creating the post. This would allow you to do something like Post.where(week: 3)
to get all the posts that are in week 3. You could potentially automate this if you set a fixed start time, then you could just calculate how many weeks have passed since the start time to fill in the week #.
You could define a Week
model where a post belongs to a week. This would be setup similar to a Category
model in relation to a blog but I don't think it's a very efficient way to handle this particular scenario, but I could be totally wrong.
You could also look into the groupdate gem which would allow you to group records together based on a given time range at the time of your query. This is probably the "right" way to do it, but I believe you'd still need to define a fixed start date so you can properly count how many weeks have passed to properly label each grouping "week 1, week 2, etc..."
That's about all I can think of, there may be more clever ways to handle...
Would this gem also help me if I created 4-6 teaser boxes on my main page, in which the last 4-6 most recent posts are displayed? That would be my final goal for the main page. The boxes would then simply have the title of the post, the first two lines and an image from the post. But I really need help again, because I have no idea how to address the image in order to load it dynamically into the box. Thank you for your great help! I'm slowly learning to really love Ruby on Rails and have a lot of fun in the ever new challenges I'm facing.
For the boxes on the home page, if you just need the last 4-6 posts just do something like Post.last(4)
, no need to use the gem for that one.
Chris has some great videos on managing files / images. Check out https://gorails.com/series/direct-uploads-to-amazon-s3 - after going through those you should have no problem dispaying whatever photos you want along with your posts.
Glad I could help! Have fun!
Yeah well the problem is not to upload the images into my post, the problem is to call them later from the post. E.g. i have a box with a title field a description field and an image field. Now i want to get the title, the description and the image automatically from the post i created into that box. And everytime i create a post the title, description and the image of the box is changing.
I guess therefore i have to call the image FROM the post, which i had uploaded via trix and shrine nearly as chris described in his videos
Ah, yeah this is basic MVC
In your controller you'll have something like:
class VisitorsController < ApplicationController
def index
@latest_posts = Post.last(4)
end
end
then in your app/views/visitors/index.html.erb
you'll iterate over @latest_posts
and output the relevant data there... something like:
<% @latest_posts.each do |post| %>
<h1><%= post.title %></h1>
<p><%= post.description %></p>
<%= image_tag post.image_url %>
<% end %>
Thank you for your help i think my problem is to get the association between my post and the image.
someone at SO mentioned that:
# db/migrations/001_create_photos.rb
create_table :images do |t|
t.integer :imageable_id
t.string :imageable_type
t.text :image_data
t.text :image_signature
end
add_index :images, :image_signature, unique: true
# app/uploaders/image_uploader.rb
class ImageUploader < Shrine
plugin :signature
plugin :add_metadata
plugin :metadata_attributes :md5 => :signature
add_metadata(:md5) { |io| calculate_signature(io) }
end
# app/models/image.rb
class Image < ApplicationRecord
include ImageUploader::Attachment.new(:image)
belongs_to :imageable, polymorphic: true
validates_uniqueness_of :image_signature
end
Also for consistencies sake in your code either call it image or photo. Your uploader is called Photos but everywhere else it is called Image.
The last change you need is in your controller for it to accept an array of images instead of one image. To do that you need to simply use an array:
def show
@image = Image.order('RANDOM()').limit(1).first
end
private
def images_params
params.require(:images).permit(images: [)
end
But iam not really sure what he meant with the first part, do i have to change my create_image model ? And if so how do i migrate it like that without killing everything? I still find the migration thing pretty confusing to be honest.
Can you link to the SO question so I could see what he's referencing, and do you by chance have the ability to share the repo?
From the sounds of it, you're wanting the ability to attach multiple photos to a single post. If so you can ignore my last message as that was if you only had a single file attached to the Post model.
- Also for consistencies sake in your code either call it image or photo.
Is this what you're unsure of? If so, all he's saying is to have continuity in your naming conventions. Imagine you're reading a book, and for no reason the main character's name changes. Then a few sentences later, they're back to calling the character by their original name. Doesn't make much sense to do that does it?
- How do i migrate it like that without killing everything?
Since I can't see what you named everything, I don't want to make assumptions and cause any further confusion. If you can provide the SO link and/or repo I can take a look and see if I can help explain.
For migrations, check out: https://www.driftingruby.com/episodes/activerecord-migrations (should be a free episode). All a migation is doing, super simplified for the sake of brevity, is setting up your database with a table and its respective attributes (columns), or updating an exisiting table. Its just your way of managing the structure of your database.
Sure man, sorry. Here is my SO Link: https://stackoverflow.com/questions/51912749/rails-calling-an-image-from-an-article-which-is-uploaded-in-the-article-via-shri/51912838#51912838
no, i get that inconsitency thing on the other hand i am not really sure why he is then referring to a create_photo migration, maybe thats what confusing me.
Ah my gitrepo is here: https://github.com/WebSepp/Blogapp
Ahhh ok, I should have paid a bit more attention to the actual Trix implementation.
The Trix editor is uploading the images and creating the Photo object as soon as you drag + drop them into the text area. The problem is your Post hasn't been saved yet, which means it doesn't have an ID so you can't associate the Image to the Post at the database level.
There's probably a few ways to handle this, one off the top of my head would be to first add post_id to the Image
model.
rails g migration addPostIdToImages post:references
which should give you
class AddPostToImages < ActiveRecord::Migration[5.2]
def change
add_reference :images, :post, foreign_key: true
end
end
Then add your associations to your Post
and Image
models
class Post < ApplicationRecord
has_many :images
end
class Image < ApplicationRecord
belongs_to :post
end
Now you need to have the xhr request return the ID of each saved photo and load it into an array to be passed with the post attributes upon save. To do this, you need to first create a hidden field to hold the array of image_ids
app/views/posts/new.html.erb
(you really should be using the _form.html.erb
partial, but this is based on your repo)
<%=form_for @post do |form| %>
...
<%= form.hidden_field :image_ids %>
...
<% end %>
then update trix_attachments.js
to update the value of the hidden field on each upload
app/assets/javascripts/trix_attachments.js
xhr.onload = function() {
if (this.status >= 200 && this.status < 300) {
var data = JSON.parse(this.responseText);
var image_ids_input = $("#post_image_ids");
var image_ids = image_ids_input.val() ? JSON.parse(image_ids_input.val()) : []
image_ids.push(data.image_id);
image_ids_input.val(JSON.stringify(image_ids));
return attachment.setAttributes({
url: data.url,
href: data.url,
});
}
};
In your post create
action, you could take those ID's and assign them to the images
def create
@post = Post.new(post_params)
if @post.save
image_ids = params['post']['image_ids']
image_ids = image_ids.present? ? JSON.parse(image_ids) : nil
if image_ids.present?
Image.where(id: image_ids).update_all(post_id: @post.id)
end
redirect_to posts_path
else
render "new"
end
end
Now you can get your images by its association with images, and since you want a random image, you can do
app/views/posts/index.html.erb
<% @posts.each do |post| %>
...
<%= image_tag post.images.offset(rand(post.images.count)).first.image_url if post.images.present? %>
...
<% end %>
which will select one random image and display it if there are any attached images to that post.
Sorry if multiple posts are happening, everytime I paste my reply and save, it eats it up and isn't showing as being posted on my end.
Shortening it down and attaching the bulk as a github gist -
I should have paid a bit more attention to the actual Trix implementation...
The Trix editor is uploading the images and creating the Photo object as soon as you drag + drop them into the text area. The problem is your Post hasn't been saved yet, which means it doesn't have an ID so you can't associate the Image to the Post at the database level.
Here's the gist with the rest: https://gist.github.com/nanosplit/585cb1776422199e3fce7b7ed4dae615
First of all thank you very much for your incredible efforts to help me!
Unfortunately there seems to be an error:
<%= image_tag post.images.offset(rand(post.images.count)).first.image_url if post.images.present? %>
shows up that "images" are not find. Maybe there is an error now with the photo uploader? Or the name image? Sometimes referred as image and sometimes as images, while images seems to be an issue, not sure.
The /new form is rendering perfectly and i still can drag an drop an image, but it wont show up anymore. Neither in the singleview, nor in the teaserbox on /index.
I updated my GitRepo again, i think my schema looks fine, but there has to be an error now with the upload in general right ?
Would really appreciate it if you could have a look.
Seems like something if really odd with the upload, cause when i look for Image.all in the DB there isnt any entry at all.
https://github.com/WebSepp/Blogapp
- i really should change the title of the thread cause its going in another direction now, which is hopefully also helpful for others using trix and shrine.
Ah, ok one thing I forgot to include in the gist was the update to your images controller so it returns the ID... so in app/controllers/images_controller.rb
you need to change:
format.json { render json: { url: @image.image_url }, status: :ok }
to
format.json { render json: { image_id: @image.id, url: @image.image_url }, status: :ok }
So that's one thing...
Oh, another I forgot was you need to rename a few things... we're going to stick with the convention images
instead of photos
since you mainly use images
. So your app/uploaders/photo_uploader.rb
needs to be renamed to app/uploaders/image_uploader.rb
and also update the class inside from PhotoUploader
to ImageUploader
. Now head over to your Image
model and change the include from include ::PhotoUploader::Attachment.new(:image)
to include ::ImageUploader::Attachment.new(:image)
and that should fix your upload problems.
Another I just noticed while looking at the repo was in app/controllers/posts_controller.rb
in your index
action, you have:
def index
@posts = Post.all
@posts = Post.order(date_field: :desc)
end
Just update it to:
def index
@posts = Post.order(created_at: :desc)
end
I assume date_field
is just a copy/paste error from the group_date gem. Also, since you are now needing the images when you display them on the index, you may consider using includes
so the association is loaded with includes(:images)
... so now your index action would be @posts = Post.order(created_at: :desc).includes(:images)
. This just helps speed things up a bit, probably won't be noticeable for such a simple setup but it's a good habit to get into.
Let me know how that works - also note that any of your old posts + images aren't going to be associated since the association is made at the time of saving the post. So you'll have to manually make those associations if there's any. If there are, just add the respective post_id
value to the image.
Thank you again, yeah unfortunately its still not working - i dont really get, why its sometimes :image and sometimes :images is that right?
DB still says no image, so something on the Uploader is still not correct. Maybe i missed something or did something wrong. :(
date_field is correct i think, it gives me the opportunity to select a date for my posts and order it by the date, which could be helpful if i dont want to have it orderd by the creation_date. Maybe the choice of the name wasnt a really smart move from me.
Old posts and images are not a problem, its everything just local right now to test it and set it up
Did i implemented the js correct? And did the images from the posts still should show up like normal in all_weeks where i call the content?
- date_field is correct i think
Doh, you're right. I read through the schema too fast and mis-read the field. Sorry for the confusion. Although you may consider renaming it publish_date
or something a little less ambiguous.
app/models/image.rb
you need to include optional: true
on your belongs_to :post
declaration (sorry that was my fault, I forgot to add it to the gist). I bet if you look in your logs as you try to attach an image you'll get an error saying post_id
is missing. As of Rails 5, belongs_to associations must have an association ID on save. However, for your situation that doesn't jive, so you need to add the optional flag so it can save. I bet this is why you're not getting any images saved. - see: https://blog.bigbinary.com/2016/02/15/rails-5-makes-belong-to-association-required-by-default.html
- Did i implemented the js correct?
Looks right to me, I'm 99% certain the optional: true
flag is what's causing your problem right now.
- And did the images from the posts still should show up like normal in all_weeks where i call the content?
Yes, you'll still have the embedded image in your post as before, just now you also have an association to those image objects so you can display images without having to also display the contents of the blog post. So if all you want to display is the title of the blog post and the first image, you can do that now with @post.title
and @post.images.first.image_url
Man you are a genius! Thank you so much, cant express how much you helped me! Its totally working now! Thank you i really really appreciate it!
Now i can work on my other 1000 problems :P
Haha, damn now i got a pretty difficult problem, when i want to refer to post.content i often dont want to have the image but only the text, for example for the teasertext. How can i manage that one?
You are the best!
Aye no problem!
As for your other problem, you could use the strip_tags
helper strip_tags(@post.content)
which should take care of any basic HTML. You could also create a new column, something like intro_text
that would allow you to display that text instead and reserve the content
for the full blog post. If you decide to use strip_tags
, take a look at the truncate
helper as well since you'll probably want to truncate the text at some point and provide a "read more" link.
Wow, you can't imagine how much you helped me. Thank you. I think I learned a lot already, because I started to write my own blog as a Rails application, but I have to admit, that it was not a good idea to use it myself and to present it later to others, probably my experience with Rails is not enough. Currently, for example, I still have a lot of code that actually belongs in the controller in the view or? But I'm not sure where exactly to outsource it. Thats getting more and more an issue, i think one where i ran recently in is this line in all_posts.html.erb
<%= link_to image_tag(post.images.last.image_url), post %>
if the last post has no image the image_url wont work and rails is throwing an error, so yeah iam supposed to do an if post.images.last.present? or something, but i dont really know where, cause i think an if loop in the link_to isnt really possible.
Especially the all_posts.html.erb shouldnt be like it is currently right?
I mean if i would like to add some functionality i cant to that like for posts cause there is the posts_controller.
My whole structure seems to be a bit off, also my index page, or what is supposed to be my index page is reached under localhost:3000/posts while it would be better under localhost:3000 itself, or even /index or something like that right?
Anyway ill try to finalize it as good as i can and try to deploy it, so maybe i can try to use it - if so, i think many credits go to your wonderful help! I really appreciate it. - Maybe i should try to read more about the basics first, and then come back one day and optimize it - but obviously the try and error thing is more fun, at least if a little success results from it.
All in all, I have to admit to myself that I still understand very little about web development, but I saw your motivations post in another thread that I found really very inspiring. Thanks again for your incredible help :)