So I am setting up previous post links in my Rails app and have the following in my show:
<% if #post.previous.blog_key == 'blog' && #post.previous.visible == true %>
<%= link_to 'previous post', blog_post_path(#post.previous.url_name%>
<% else %>
<%= link_to 'Home', '/blog/home' %>
<% end %>
Then in my model I have:
def previous
SpudPost.where(["published_at < ?", published_at]).last
end
def next
SpudPost.where(["published_at > ?", published_at]).first
end
What I'm trying to do is only have the previous links to go to those blog posts that are marked as having a blog_key that says blog AND marked to be visible. If it's not blog/false then ignore it and go to the next one that says blog and visible.
The problem is that it doesn't go to the next one that says blog/true. If the next one says blog_key == 'news' then it applies to 'Home'. Should it just be another filter within the previous/next methods instead?
Model works better.
def previous
SpudPost.where(blog_key: 'blog').where(visible: true).where(['published_at < ?', published_at]).last
end
def next
SpudPost.where(blog_key: 'blog').where(visible: true).find_by(['published_at > ?', published_at])
end
Related
I don't even know how to phrase the question. I have a blog with a feed. When a person clicks through to the show page, I would like to have a link with the image to the next article in a right sidebar. When it gets to the first article in the database or the newest one I either don't want a link with a picture or maybe one to the oldest story in the databse to loop back around.
I have code working where it gets the next article and displays its cover photo with a link to it. If somone could help me write the conidtion for the first article in the databse so I don't get errors that'd be great. Here's the code I have:
the show page:
<div id="next-story-sidebar">
<%= link_to "next story", #next_home_blog, style: "font-size:20px;" %>
<%= image_tag #next_home_blog.image.to_s, style: "width:60px;height:60px;" %>
</div>
home_blog.rb
def next
self.class.where("id > ?", id).first
end
def previous
self.class.where("id < ?", id).last
end
def last
self.class.where("id = ?", id).last
end
home_blogs_controller.rb
def show
#home_blog = HomeBlog.find(params[:id])
#next_home_blog = #home_blog.next
end
error when I click the next story link which takes me to the first article in the database: undefined method `image' for nil:NilClass
It is because you need a base case for your queries.
self.class.where("id > ?", id).first
The issue is that if you have id of 1,2,3 and you are on number 3. This will return a 0 length collection and first on an empty collection it is nil.
To fix this you can either do nil checking everywhere in your app
<% if #next_home_blog %>
<div id="next-story-sidebar">
<%= link_to "next story", #next_home_blog, style: "font-size:20px;" %>
<%= image_tag #next_home_blog.image.to_s, style: "width:60px;height:60px;" %>
</div>
<% end %>
Or do something where you return a NullBlog to represent that concept and handle it more OO style. Here is a link to the NullObject pattern to get you starting if you want to investigate that. https://robots.thoughtbot.com/rails-refactoring-example-introduce-null-object
I created a rails app that allows the user to read a magazine.
To do so, I created two scaffolds, one for the magazine and an other for the pages inside of it. I then made a one-to-many relationship, so the pages belong to the magazine.
Each page is an image, since they are digitized then uploaded in a multi-upload form.
Recently, the group I work for asked me to find a way to allow the user to read two pages at the same time, so I made some tweaks, and it works like a charm.
However, I now have a problem: I want to set some "previous" and "next" links, but I can't find a way to do so
Here is what I have done so far:
magazine_controller.rb
def create
#magazine = Magazine.new(magazine_params)
if #magazine.save
#index = 0
(params[:images] || []).each_with_index do |image, index|
if index.even?
#This way, #index increments every other upload
#So I'm sure I have two images with the same page_number
#index += 1
end
#magazine.pages.create(image: image, page_number: #index)
end
redirect_to #magazine, notice: 'Magazine créé'
else
render :new
end
end
models/page.rb
class Page < ApplicationRecord
belongs_to :magazine
validates_presence_of :magazine
mount_uploader :image, PageUploader
def previous
self.class.first.where('page_number < ?', page_number).limit(1).first
end
def next
self.class.first.where('page_number > ?', page_number).limit(1).last
end
end
views/pages/show.html.erb
<% #page.each do |p| %>
<%= image_tag p.image %>
<%= p.inspect %>
<% end %>
<br />
<%= #page.first.page_number %>
<%= link_to '< Précédent', magazine_page_path(magazine_id: #magazine.slug, id: #page.previous) if #page.previous %>
<%= link_to 'Suivant >', magazine_page_path(magazine_id: #magazine.slug, id: #page.next) if #page.next %>
<br />
<%= link_to 'Back', magazines_path %>
page_controller.rb
private
def set_page
#magazine = Magazine.find_by(slug: params[:magazine_id])
#was 'find_by' before I was asked to show two records at the same time
#page = #magazine.pages.where(page_number: params[:id])
end
So with this code, I'm getting the error undefined method 'previous' for #<Page::ActiveRecord_AssociationRelation:0x007ff4f702ad48>. I don't have a clue about how to find if there is a following "page" or not.
Any idea welcome!
Thank you in advance
Remember that #page is no longer a single record, it's an association with two records.
You can create previous and next page methods in Page class for the association instead of the object (self.previous instead of previous). It will get a new association for the previous (or next) page number. Note the addiitional code to make sure you're getting the same magazine (which you don't have in your current code that worked for single pages).
Also note that if the association has no records (count == 0) the methods return nil... this is to accommodate your if #page.previous test for no previous (and if #page.next if no next)
def self.previous
new_page_set = Page.where(page_number: (first.page_number - 1), magazine: first.magazine)
return new_page_set.count == 0 ? nil : page_set
end
def self.next
new_page_set = Page.where(page_numberL (first.page_number + 1), magazine: first.magazine)
return new_page_set.count == 0 ? nil : page_set
end
I'm trying to figure out at this point how to display only a certain amount of categories based on a user plan. So in my controller I have the following;
def check_plan?
User.current.plan_id == "" && User.current.bins.count == 2 || User.current.plan_id == "nil" && User.current.bins.count == 2
end
helper_method :check_plan?
NOTE: I know, not pretty but it will do for now. So basically :check_plan? checks a few things.
Now I thought, that I could use that for our category list as a starting point, so that if the user isn't on any plan, they are limited in showing 2 if they are on a plan it shows them all. Here's what I thought would work but it doesn't. I've done it before but can't remember exactly how it went, so any help is appreciated.
<% if check_plan? %>
<% #bin_list.order("position").limit(2).each do |bin| %>
<% else %>
<% #bins_list.order("position").each do |bin| %>
<% end %>
Not really working and I know why, but their will all my other tries with bringing any of those lines together with check_plan.
Such logic belongs to Model natually. Don't abuse helper.
class User < ActiveRecord::Base
def bin_limit
check_plan? ? 0 : 2
end
def check_plan?
# Your logic
end
def bins_with_limit
bins.with_limit(bin_limit)
end
end
class Bin < ActiveRecord::Base
def self.with_limit(limit)
return self if limit <=0
self.limit(limit)
end
end
View
current_user.bins_with_limit.each do |bin|
First of all, the rails method .blank? will return true for either "" or nil, so you can start by refactoring your code as follows:
def check_plan?
( User.current.plan_id.nil? || User.current.plan_id.blank? ) && User.current.bins.count == 2
end
helper_method :check_plan?
Secondly, you're calling blocks in the code below, so you'll need to complete them with end
<% if check_plan? %>
<% #bin_list.order("position").limit(2).each do |bin| %>
<% end %>
<% else %>
<% #bins_list.order("position").each do |bin| %>
<% end %>
<% end %>
Of course, you'll want to put whatever you're doing with bin between the do and end portions above.
Come across a little stumbling block when linking to a post within my app. I am truncating the text of a post and providing a 'Read More' link. There are 2 areas where posts are viewed, one for everyone ( public) and also one for the admin user to edit/delete posts.
So in my public view I am doing this
<% #toppost.each do |t| %>
<div class="post-item">
<h2><%= t.title %></h2>
<ul id="newsHome">
<li><%= date_output(t.published_on) %></li>
<li><%= t.department.name %></li>
<li>by Admin</li>
</ul>
<% if t.comments.length > 350 %>
<p class="post-description"><%= truncate(t.comments, length: 350).html_safe %>
<%= link_to '...Read more', t %></p>
<% else %>
<p class="post-description"><%= t.comments.html_safe %></p>
<% end %>
</div>
<% end %>
However when clicking read more it takes me to the url
/posts/:id
which is actually the place where an admin user views posts, so at the moment a user will get redirected back to the home page as the posts controller has
before_filter :authenticate_user!
The place where all posts are viewed publicly are on specific news pages , for example
localhost:3000/tynewyddnews
localhost:3000/woodside
localhost:3000/sandpiper
localhost:3000/outreach
My question is how to link to that post at its location in the public part of the site.
Index action where top_posts method used(see below for method)
def index
#title = 'Home'
#toppost = Post.top_posts
end
top_posts method
def self.top_posts
#Array with each of the 4 departments - first record
top_posts = [
self.tynewydd_posts.first,
self.woodside_posts.first,
self.sandpiper_posts.first,
self.outreach_posts.first
]
#remove entry if nil
top_posts.delete_if {|x| x==nil}
return top_posts
end
Controller
def tynewyddnews
#title = 'Ty Newydd News'
tynewyddpost = Post.tynewydd_posts.reverse
tynewyddpost.pop
#tynewyddpost = tynewyddpost
#tynewyddpostlatest = Post.tynewydd_posts.first
end
Model
scope :tynewydd_posts, :include => :department, :conditions => {"departments.name" => "Ty Newydd"}, :order => "posts.published_on DESC"
There are another 3 scopes for the other departments, all the same looking for the condition department name
Hopefully ive added enough info, anything else needed please ask
EDIT
Been thinking this through and not sure if im on right track, but for each post i need it to link to its appropriate news page in the public pages controller.
tynewyddnews
sandpipernews
outreachnews
Woodsidenews
So in my link_to i need to pass a route to the appropriate action depending upon the type of post.. so how to give each post a type and then link to that?
Thanks
Wow, ok, where do I begin.
You need a route that points to that controller action, for example
`get '/tynewyddnews' => 'news#tynewyddnews', :as => 'public_news' # gives you the route public_news_path
in your view
= link_to 'Read More', public_news_path
So ya, that should do it. BTW you can also use the .truncate() method. You pass in the length as an argument, and it adds the ... for you
I'm building a small ecommerce site that sells a variety of mens and womens clothing. i would like to render a partial based on which taxonomy the user is in. For example, if the user is at mysite.com/t/women/pants I would like to render _women.html.erb, or, if the user is at mysite.com/t/men/shirts I would like to render _men.html.erb.
I have a Taxonomy model that has_many taxons, and the Taxon model has_many products.
In taxons_controller.rb I have:
def show
#taxon = Taxon.find_by_permalink(params[:id])
return unless #taxon
#taxonomy = Spree::Taxonomy.all
#taxon_title = Spree::Taxon.all
#searcher = Spree::Config.searcher_class.new(params.merge(:taxon => #taxon.id))
#searcher.current_user = try_spree_current_user
#searcher.current_currency = current_currency
#products = #searcher.retrieve_products
respond_with(#taxon)
end
And in taxons#show I have: (which I know is wrong)
<% #taxon_title.each do |title| %>
<% #taxonomy.each do |taxonomy| %>
<% if title.name == taxonomy.name %>
<%= render "spree/shared/#{title.name.downcase}" %>
<% end %>
<% end %>
<% end %>
When I go to mysite.com/t/women/long-sleeve the rails debugger displays :
controller: spree/taxons
action: show
id: women/long-sleeve
How do I access the id of the action im inside, so that in the controller/view I can do something like:
'if id equals 'women' render "spree/shared/#{title.name.downcase}"'
where title is the name of the taxonomy?
I imagine I need to find(params[:something] in the show action of the controller, but I'm a little unclear about params.
*
*
*
#beck03076 That's a great trick. Thank you very much. But it's still not working.
In my controller I put:
#taxon_id = Spree::Taxon.find(params[:id])
Then in the action I put:
render 'spree/shared/women' if #taxon_id == params[:id]
And when I load the page it says 'the page you were looking for doesn't exist'. My partial is in the correct directory. Is my syntax correct?
My params are:
{"controller"=>"spree/taxons", "action"=>"show", "id"=>"women/long-sleeve"}
Thanks again for your help!
Whenever you are unclear about params, just put the lines below in the action and execute the action.
p "****************************"
p params
p "****************************"
Now, goto the terminal in which you started your server.
Locate those two "*******" and everything thats in between them are params.
params is basically a ruby hash.
example:
params look like this, {:controller => "hello",:action => "bye", :id => 7, :others => "OK"}
In your controller to access the id, use params[:id].(=7)
to access others, use params[:others].(="OK")