Check if next active record exists - ruby-on-rails-4

In posts controller an object contains all active posts:
#posts = Post.where(status: 'active').order(:name)
In the view this object is iterated and I have to perform some operations based of the existence of next post.
<% #posts.each do |post|
if post.next_post_exists?
# do something.
else
# delete author.
end
end
%>
So, what is the best way to check if the next post exists?
def next_post_exists?
#TODO
end

You can simply take a variable for the current post and then check for the presence of the next post.
For example:
<%i=0
#posts.each do |post|
if #posts[i+1].present?
#do something
else
#delete author
end
i+=1
end%>
Try this and let me know if it works.

class Post
def next
self.class.find_by("id > ?", id)
end
end
And at this point you can do:
<% #posts.each do |post|
if post.next.present?
# do something.
else
# delete author.
end
end
%>

Related

How do I render a page for nested routes

To learn rails, I started to write my own (stripped down) version of reddit. Currently, I have my comments routes nested inside my post routes as such:
resources :posts do
resources :comments
end
For my comments controller, under index & create I have the following
def index
#post = Post.find(params[:post_id])
#comments = #post.comments
if params[:comment].nil?
#comment = Comment.new
#comment.post_id = #post.id
else
#comment = Comment.find([:comment])
end
end
def create
#comment = Comment.new(comment_params)
#comment.user_id = current_user.id
#comment.post_id = params[:post_id]
if #comment.save
#flash
redirect_to post_path(#comment.post)
else
#flash
render 'index'
end
end
Which works well, except the last part: render
I want my comments to display on the same page as the other comments (just like reddit), so I would prefer not use the www.example.com/post/4/comment/new path, and instead do it through the www.example.com/post/4/comments path.
I understand that I can do a redirect, however I want to keep the comment text, so the user can make corrections. Is there a way to properly do this with a render, as opposed to me putting the text in a session variable and doing a redirect? I understand this is an edge case, but am trying to use this as a learning opportunity.
You can pass the comment to the index partial - no?
<%= render "index", locals: {comment: #comment} %>
Or try a partial;
<%= render partial: "index", locals: {comment: #comment} %>

Rails 4 Fragment Cache Entire Page. How to Expire Cache In Model

How do I expire the main-page fragment in a model?
In my HTML
<% cache 'main-page' do %>
# html here
<% end %>
In my Post Model
after_create :clear_cache
after_update :clear_cache
def clear_cache
ActionController::Base.new.expire_fragment('main-page')
end
This doesn't clear the cache. If I create or update a post, the cache doesn't clear. If I run ActionController::Base.new.expire_fragment('main-page') in rails console it returns 'nil'. If I run Rails.cache.clear instead of ActionController::Base.new.expire_fragment('main-page') in the post model, it works.
I believe your issue is the digest, so if you change your cache to this it should work:
<% cache 'main-page', skip_digest: true do %>
# html here
<% end %>
If you want to use this kind of style, where the cache doesn't expire and relies on detecting model changes to invalidate, you may want to consider using an Observer or Sweeper, which were removed from Rails 4, but are useful for this pattern:
https://github.com/rails/rails-observers
Not the answer you are looking for perhaps, but another way:
Make the cache key based on the max updated_at from the Post model.
Whenever any post changes, the cache key will automatically miss and go retrieve the latest posts to re-cache that part of the view.
module HomeHelper
def cache_key_for_posts
count = Post.count
max_updated_at = Post.maximum(:updated_at).try(:utc).try(:to_s, :number)
"posts/all-#{count}-#{max_updated_at}"
end
end
And then in your view:
<% cache cache_key_for_posts, skip_digest: true do %>
# html here
<% end %>

Calling a wicked wizard step multiple times

I built a multistep form with wicked-gem consisting of three steps.
The last step should be callable 1 to x times.
So I added another button to my form:
if current_step?(:add_principal_claim)
= file.submit value: 'next_claim', class: 'button tiny radius'
= link_to 'finish', Wicked::FINISH_STEP, method: :put, class: 'button tiny radius'
and add another step in my controller
steps :add_file_header, :add_claim_header, :add_principal_claim, :next_principal_claim
def show
if step == :add_claim_header
case step
when :next_principal_claim
redirect_to wizard_path(:add_principal_claim)
else
render_wizard
end
end
end
The last needed step is :add_principal_claim. If neccessary it should be called several times to store more than one dataset to the model.
Calling the form from the previuos step leads into show action and renders the add_principal_claim view, clicking the file.submit button leads to the update action in the controller, stores the dataset into the model and recalls the add_principal_claim view as intended.
How can I get the link_to button to jump into update action, store the dataset and then finally jump out of the wizard?
Any suggestion would be appreciated.
For those with the same problem: I added another step called :finish and in the form I now have two submit buttons with different values of course, here called 'next_principal_claim' and 'finish'.
def show
if params[:commit] == next_principal_claim
redirect_to wizard_path(:add_principal_claim)
elsif params[:commit] == finish
redirect_to project_path(#project)
else
render_wizard
end
end
That works fine for me!

If else check for ujs file

I am building an Rails 4.1 webapp and I am using a an ajax form (remote true)
and a create.js.erb file with this content:
$("div.box-content").prepend('<%=j render #comment %>');
$(".empty-message").hide();
$(".textfield").val("");
How can I check if #comment is empty?
Right now it´s adding an empty row when there is no content (I don't want to add a row if comment is not set).
Update
def create
#comment = #object.comments.create(comments_params)
end
You can either check server-side (conditionally output different JavaScript) or you can check in client-side in JavaScript.
Checking server-side involves testing whether #comment is set, and simply not output any of the prepending JavaScript:
<% if #comment.present? %>
$("div.box-content").prepend('<%=j render #comment %>');
<% end %>
$(".empty-message").hide();
$(".textfield").val("");
Checking client-side involves outputting the empty value in a variable so you can inspect it in JavaScript vefore prepending it to your element:
var comment = '<%= j render #comment %>';
if (comment) {
$("div.box-content").prepend(comment);
}
$(".empty-message").hide();
$(".textfield").val("");
I would use the first approach.

Need help passing dynamic list of files to partial. Can't get list to pass successfully in Rails

In my application/index, the user selects a location and directory path from a drop down list. onchange event makes a call to the controller called file_dir where it takes the path, executes a command line call passing back a list of files in that directory to a parameter #files. I then render a partial passing this #files to a local variable. Then in the partial the select tag will display with the list of file passed to it.
I am new to ROR and have not been able to successfully pass a readable local variable. to the partial. Everything works fine with a hardcoded line but not with the local variable.
Can someone please help advise me on the correct way to set this up?
Here is the method called from the first onchange dropdown pass that receives the directory:
def file_dir
unless params[:dir_list].nil?
#dir_path_choice = params[:dir_list]
else
#dir_path_choice = '/watchfolder/indemandvod'
end
# #files = "#{#dir}"
#files = Dir.glob("#{#dir_path_choice}/**/*.{mpg,mov}").map
if #files.nil?
#files = Dir.glob("/watchfolder/hbovod/**/*.{mpg,mov}").map
end
render :partial => 'list_files', :locals => { #list => #files }
end
In irb I tested the #files = Dir.glob("#{#dir_path_choice}/**/*.{mpg,mov}").map line to make sure this was processing correctly. Here is what #files looks like:
1.9.3-p547 :008 > #files
=> #<Enumerator: ["/watchfolder/indemandvod/MJR-TEST.mov", "/watchfolder/indemandvod/MJR-TEST-AWS1.mov", "/watchfolder/indemandvod/MJR-TEST-AWS.mov", "/watchfolder/indemandvod/MJR-TEST2.mov", "/watchfolder/indemandvod/PIX_Gor_SVO40185/PIX_Gor_SVO40185_mezz.mov"]:map>
This data breaks out in the select list, separated by the commas.
NOTE: I did try to pass the #list without the # symbol but I got unidentified local variable or method and couldn't get the code to run with out adding the #. This is like a collection of data so I expect it is interpreting it as an array. Not sure though.
Here is the partial file code:
<p>
<label>Select Partial Test File List:</label><%= #list %><br />
<% unless #list.nil? %>
<%= #list %>
<% else %>
<label> list is empty. </label>
<% #list = Dir.glob("/watchfolder/showtimevod/**/*.{mpg,mov}").map %>
<% end %>
<%= select_tag 'filepath', options_for_select(#list, #selected_filepath) %>
</p>
It does display back on the page and my 'list is empty' always shows and the dropdown box populates with my default 'hardcoded' command line for '/watchfolder/showtimevod/' files list.
The #selected_filepath maintains the selected line in the list.
I don't know what I am doing wrong in passing values to partials.
In my application/index,
What is an "application/index"?
Can someone please help advise me on the correct way to set this up?
The correct way is to get something simple to work first:
app/controllers/some_controller.rb
def file_dir
puts "****#{params[:dir_list]}"
#files = %w[ a b c]
render :partial => 'list_files', :locals => { file_names => #files }
end
views/some_controller/_list_files.htm.erb:
<div>
<%= file_names.each do |fname| %>
<div><%= fname %></div>
<% end %>
</div>
And as with all your posts, in this line:
<%= select_tag(
'filepath',
options_for_select(#list, #selected_filepath) %>
#selected_filepath is undefined.
This is like a collection of data so I expect it is interpreting it as
an array. Not sure though.
You should probably strive to create data that you understand. What are you trying to accomplish with this line:
#files = Dir.glob("#{#dir_path_choice}/**/*.{mpg,mov}").map
that the following line doesn't do:
#files = Dir.glob("#{#dir_path_choice}/**/*.{mpg,mov}")
This:
I did try to pass the #list without the # symbol but I got
unidentified local variable or method and couldn't get the code to run
with out adding the #.
is not sufficient. No one cares what your interpretation of the error message is--what people care about is the EXACT error message, with file names and line numbers, copy and pasted into your post, along with the exact code the error refers to.
If you just want to get your code to work, you can do this:
app/some_controller.rb:
def file_dir
if params[:dir_list].nil?
#dir_path_choice = '/watchfolder/indemandvod'
else
#dir_path_choice = params[:dir_list]
end
#files = Dir.glob("#{#dir_path_choice}/**/*.{mpg,mov}").map
if #files.nil?
#files = Dir.glob("/watchfolder/hbovod/**/*.{mpg,mov}").map
end
render :partial => 'list_files', :locals => {file_names => #files }
end
However, adding map() to the end of your Dir.glob() does nothing useful.
app/views/some_controller/_list_files.html.erb:
<p>
<label>Select Partial Test File List:</label>
<%= select_tag 'filepath', options_for_select(file_names) %>
</p>