Ruby on rails: What is the most simple way to show one post per page with permalink - ajax

Right now under my posts controller i have methods
def main
#post = Post.all
end
def show
#post = Post.find(params[:id])
end
I am wondering what is the most basic and simple way to show one post per page and have next and previous links to it. Here i am referencing to main.html.erb . So for instance just have localhost:3000/posts and under that page i can have next and previous links to browse through the post.
Would I be needing some kind of ajax to this? If not then how i can do this using simple activerecord and other elements of rails?
Note: After I click on next, i do need to have the permalink of the post in the url tab.

You could do something like this. Add previous and next method to your model
def previous
posts = where('id > ?', id).limit(1)
if posts.nil?
nil
else
posts.first
end
end
def next
posts = where('id < ?',id).limit(1)
if posts.nil?
nil
else
posts.first
end
end
and then in your view you could do something like this.
unless #post.next.nil? #to show the link to the next post
link_to #post.next
end
unless #post.previous.nil? #to show the link to the next post
link_to #post.previous
end
Anyhow this method isn't that optimized since you will add more two more database queries to get previous and next posts.

You could use the gem will_paginate and set the default per page to 1, as in:
class Post
self.per_page = 1
end
For more information about will_paginate:
https://github.com/mislav/will_paginate

Related

Rails 4 Close current tab from controller

So, I have this html.erb and this controller (shown below). What I want is to, if simple_captcha.valid? to increment reports, save, AND close current tab. I want to do it from controller, if possible! (And also, would it be a good practice?)
I saw several examples of this done on view page using javascript, but I know nothing of javascript and, if possible, I'd like to deal with it on controller. But, in case I really have to learn javascript to achieve what I want, which direction should I take?
#view (html.erb)
<h4>To report, complete captcha</h4>
<%= show_simple_captcha %>
<%= button_to "report post", create_report_post_path(#forum_post.id) %>
-----------------------------------
#controller
def new_report_post
#forum_post = ForumPost.find(params[:id])
end
def create_report_post
#forum_post = ForumPost.find(params[:id])
if simple_captcha_valid?
#forum_post.reports += 1
#forum_post.save
redirect_to ???
flash[:success] = "Mandou ver."
else
redirect_to report_post_path
flash[:warning] = "Captcha inválido."
end
end
I don't think, you can close a tab, unless that tab was explicitly opened by javascript.
You can refer to this question: link
If however, you are opening the view using javascript. you can send window.close() using a js.erb view.
Instead of redirect_to, it would be something like
respond_to do |format|
format.js { render "js_erb_view" }
end
Inside your js.erb view file,you can send
window.close()
This would only work if you send an ajax request. One of the possible solutions to make this work :)

Rails 4 : Custom routes, multiple edit forms for a single model

I have a Rails 4 app, with a Thing model that have 3 attributes : attr_1, attr_2, attr_3.
I would like to have two edit forms :
the first one would update attr_1 and attr_2
the second one would only update attr_3
I have written four methods in my things_controller.rb :
def edit
#edit form for attr_1 & attr_2
end
def edit_attr_3
#edit form for attr_3 only
end
def update
#update attr_1 & attr_2
end
def update_attr_3
#update attr_3 only
end
And here's my routes.db
resources :things do
member do
get :edit_attr_3
put :update_attr_3
end
end
Now, GET to both edit views work (/things/:id/edit and /things/:id/edit_attr_3) but on submit, the thing#update form is called both times (thing#update_attr_3 is never called)
How can I proceed to get thing#edit_attr_3 action linked to thing#update_attr_3 please ?
EDIT :
Answer, thanks to Ross & Steve Klein :
In my views, I am using bootstrap_form_for. Usually the :url parameter is optional, as standard edit/update are linked by convention. In the case of custom edit or update actions, it is necessary to specify the update path.
<%= bootstrap_form_for #thing, url: update_attr_3_thing_path(#thing) do |f| %>
<% end %>
It's hard to say without seeing the code for your form... but if you are using form_for then the route it will map to the update action in both cases (with an object that is not a new object).
To make it work with your unique update action, you will have to specify the url that form_for should use. Something like:
<%= form_for #thing, url: things_update_attr_3_path(#thing) do |f| %>
# other form stuff .......
You can use bundle exec rake routes at the command prompt to see what your current routes are, so that you now what route helper to use with form for.

How to map routes to controllers in Sinatra?

I'd like to create a simple experimental MVC framework using Sinatra.
I'd like to define resources by name "pages" for example should resolve to:
/pages (index)
/pages/new
/pages/:id/show (show)
as WELL as map to app/controllers/PagesController.rb with corresponding get('/') to be responsible for the index, post('/pages/create') be responsible for creation, etc.
Trouble is even after reading the official documentation I'm terribly confused. I imagine I need to use non-classic Sinatra model for this, but could anyone point me in the right direction?
Thank you
If you want what I think you're wanting, I do this all the time. Initially for this scheme I used the travis-api source as a reference, but essentially what you want to do is extend Sinatra::Base in a "controller" class and then mount up your individual Sinatra "controllers" in rack, something like this:
module Endpoint
def self.included(base)
base.class_eval do
set(:prefix) { "/" << name[/[^:]+$/].downcase }
end
end
end
class Users < Sinatra::Base
include Endpoint
get '/' do
#logic here
end
get '/:id' do
#logic here
end
post '/' do
#logic here
end
patch '/:id' do
#logic here
end
end
class Posts < Sinatra::Base
include Endpoint
post '/' do
#logic here
end
end
and then something like this:
class App
require "lib/endpoints/users"
require "lib/endpoints/posts"
attr_reader :app
def initialize
#app = Rack::Builder.app do
[Users, Posts].each do |e|
map(e.prefix) { run(e.new) }
end
end
end
def call(env)
app.call(env)
end
end
You can adjust this to whatever you need, but the idea is the same, you separate your app into composable Sinatra applications that each have a prefix that they are mounted under using Rack. This particular example will give you routes for:
get '/users'
get '/users/:id'
post '/users'
patch '/users/:id'
get '/posts'
I'll give you a very simple example here:
Create a file controller.rb
get '/pages' do
#pages = Pages.all
erb :pages
end
Next create a views directory in the same folder as teh controller, and create a file named pages.html.erb
This is the corresponding view to your previously created controller action.
Here, you can type something like:
<% #pages.each do |p| %>
<%= p.title %>
<% end %>
Restart your server, visit localhost:PORT/pages and you will see a list of all your page titles.
You can check out this link for a simple sinatra tutorial - http://code.tutsplus.com/tutorials/singing-with-sinatra--net-18965
You can make this as complicated or as simple as you need. For example:
Rails makes a lot of magic happen under the hood, whereas Sinatra is more flexible at the cost of requiring you to implement some of this stuff yourself.
controller_map = {
'pages' => PagesController
}
post '/:controller/new' do
c = params[:controller]
module = controller_map[c]
module.create_new()
...
end
get '/:controller/:id/show' do
c = params[:controller]
id = params[:id]
module = controller_map[c]
module.get(id)
...
end

Do calculation using radio_button variable to nested form controller - Rails 3

I have a edit form which I have a radio_button that I would like to pass to a controller action and then use it to do a calculation. In the view I have:
<div class="field">
<%= radio_button_tag(:rating_select, "Up") %>
<%= label_tag(:rating_select, "Good.") %>
<%= radio_button_tag(:rating_select, "Down")%>
<%= label_tag(:rating_select, "Bad.")%>
</div>
In the controller I have:
def rating
#post = Post.find(params[:id])
.....
end
def update
#post = Post.find(params[:id])
##rating_select = params[:rating_select]
if #post.rating_select == "Up"
#post.score += 5
elsif #post.rating_select == "Down"
#post.score -= 5
end
......
end
Currently it is ignoring the if statement so the parameter isn't getting set properly. Ideally I would like to just use a temp variable from the view to use in the if statement to decide if I need to add or subtract in the update. But I also have a rating_select field in post if I need to use it also. Thanks.
UPDATE:
Thanks. That makes sense, I changed it to below but it still isn't incrementing or decrementing the score based on the radio box. So it seems it isn't getting the rating_select?:
def update
#post = Post.find(params[:id])
if params[:rating_select]=="Up"
#post.score += 5
elsif params[:rating_select]=="Down"
#post.score -= 5
end
respond_to do |format|
....
UPDATE2:
Finally figured it out, used another model Ratings to store association. I used the before_save in the Post model and it allowed me to do the calculation and save. What a headache.
before_save :set_rating
def set_rating
if self.rating.rating_select=="Up"
rating.score += 5
elsif self.rating.rating_select=="Down"
rating.score -= 5
end
end
Well, first off, in the code you're showing the post loaded in your update action is not receiving the params from your view.
Your code for an update action should typically look like this:
def update
#post = Post.find(params[:id])
if #post.update_attributes(params[:post])
... do stuff ...
else
render :edit, :alert => 'Unable to update post.'
end
end
Second, since you're using form_tag helper and not form_for, then you're not getting the params all setup for your model (ie. nested under params[:post]). So, in this case, your rating_select option is just a value by itself, which you can test for like this:
if params[:rating_select]=="Up"
...
else
...
end
The big thing to understand from your code is #post doesn't know anything about params[:rating_select], even if you used #post.update_attributes(params[:post]), because radio_button_tag as you have it set up is not building a hash of post attributes, it's just a standalone field.
I hope that makes sense, if you don't understand please leave comments and I'll try to explain more.

getting active records to display as a plist

I'm trying to get a list of active record results to display as a plist for being consumed by the iphone. I'm using the plist gem v 3.0.
My model is called Post. And I want Post.all (or any array or Posts) to display correctly as a Plist.
I have it working fine for one Post instance:
[http://pastie.org/580902][1]
that is correct, what I would expect. To get that behavior I had to do this:
class Post < ActiveRecord::Base
def to_plist
attributes.to_plist
end
end
However, when I do a Post.all, I can't get it to display what I want. Here is what happens:
http://pastie.org/580909
I get marshalling. I want output more like this:
[http://pastie.org/580914][2]
I suppose I could just iterate the result set and append the plist strings. But seems ugly, I'm sure there is a more elegant way to do this.
I am rusty on Ruby right now, so the elegant way isn't obvious to me. Seems like I should be able to override ActiveRecord and make result-sets that pull back more than one record take the ActiveRecord::Base to_plist and make another to_plist implementation. In rails, this would go in environment.rb, right?
I took the easy way out:
private
# pass in posts resultset from finds
def posts_to_plist(posts)
plist_array = []
posts.each do |post|
plist_array << post.attributes
end
plist_array.to_plist
end
public
# GET /posts
# GET /posts.xml
def index
#posts = Post.all
##posts = [{:a=>"blah"}, {:b=>"blah2"}]
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => posts_to_plist(#posts) }
end
end
I found this page searching for the same answer. I think you have the right approach, though I'm also a newbie (on Rails) and not sure the right way to do it. I added this to application_helper.rb. Seems to work.
require 'plist'
module ApplicationHelper
class ActiveRecord::Base
public
include Plist::Emit
def to_plist
self.attribute_names.inject({}) do |attrs, name|
value = self.read_attribute(name)
if !value.nil?
attrs[name] = value
end
attrs
end
end
end
end
According to the plist project README, you should implement "to_plist_node", as opposed to "to_plist".
You should also mixin Plist::Emit to your ActiveRecord class.

Resources