Ruby on Rails: What to call in view? - ruby-on-rails

I have a next method in the model.
def self.next(comment, key = :id)
self.where("#{key} > ?", comment.send(key)).first
end
In my view I can say for example: (does not work)
= link_to "next", #comment.next(#comment)
What's the correct way to call this method?
routes.rb:
Rails.application.routes.draw do
resources :articles do
resources :comments do
end
end
end

You've defined next as a class method (vs an instance method), so you need:
= link_to "next", Comment.next(#comment)
If you want to be able to call #comment.next, define the instance method as:
def next(key = :id)
Comment.where("#{key} > ?", self.send(key)).first
end

It is not good style that the model knows this, you should put it in the controller. You should try a gem called kaminari, this gem lets you paginate over the elements, so in your comments controller you could have something like:
def show
#comment = Comment.order(id: :asc).page(params[:page]).per(1)
end
Then in your view, by just adding this kaminari helper:
<%= paginate #comment %>
You get the pagination bar below and everything works fine (gem's magic).
If you don't like this you could try to add that next method in the controller or find both next and current elements and link to the next element.
In my opinion the model is just a class that knows how to save and get information from the database and maybe some calculations with it's information, so all that logic related to the view should be elsewhere.

Related

Ruby On Rails adding new page after scaffolding

I made a scaffold named b_page and I created a migration for bio I added a biopage.html.erb
In controller:
def biopage
#b_pages = BPage.all
end
in routes.rb
resources :b_pages do
collection do
get 'biopage'
end
end
in bio.html.erb:
<div class="jumbotron">
<h1>Bio of :</h1>
<h2><b><%= #b_page.Bpage_name %></b></h2>
<h3><%= #b_page.user.email %></h3>
</div>
<%= #b_page.bio %>
but i still get the error:
ActiveRecord::RecordNotFound in BPagesController#show
Couldn't find BPage with 'id'=biopage
highlighting:
#b_page = BPage.find(params[:id])
First of all, this seems a bit odd to me:
resources :b_pages do
collection do
get 'biopage'
end
end
as it will result in a route like: /b_pages/biopage. You might want to just do something like:
resources :b_pages, except: :show
get '/biopage/:id', to: 'b_pages#show'
This way, your biopage route will go to the show controller method and you will still have the other b_pages routes to work with.
You are seeing the ActiveRecord::RecordNotFound error message because you have no BPage object to show, so the show method is complaining. Notice how the route I wrote above uses :id - this is because the show action normally takes an id of some record to display on the front end. If you want to use biopage and link it to the show method, you should be returning an object to actually show. Otherwise you should probably create a completely different controller method for biopage that does not interfere with the b_pages resources. Something like this in the routes:
resources :b_pages
get '/biopage/:id', to: 'b_pages#your_method'
and in the controller you'd have
class BPages < ApplicationController
# index, show, destroy, etc. here
def your_method
# Get whatever object you want returned here
end
end

Using form_tag my instance variables are not saving when I try to search an API

I'm trying to create a simple Rails app that will retrieve API data. My original intention were not to save the search to the database, which is why I used form_tag. My search works when I run in the console, but when I call #results or #first_match, it give me nil. Many thanks in advance.
Actor Controller Method
def index
#results = API::Topic.search([:actor])
#first_match = #results.values.first
end
Actor Form
= form_tag 'actors/show', method: :get do
= text_field_tag "Actor"
= submit_tag "Show me"
Routes
RailsApp::Application.routes.draw do
resources :actors
end
Update
Since I am routing in the show method in the form. I was able to retrieve the variables in my show method in the controller. I don't know if this is the best way though.
def show
#results = API::Topic.search([:actor])
#first_match = #results.values.first
end
I think, you need to use API::Topic.search(params[:actor])

Confused on Ruby URL parameters

I have a Questions model that has a number of different fields/parameters. If I want to view all of them, I just go to:
http://localhost:3002/questions
In order to view one specific question, I go to something like
http://localhost:3002/questions/1
How can I view the questions that satisfy a specific parameter requirement? Something like
http://localhost:3002/questions?difficulty=1
just gives the same result as viewing all questions. I know that syntactically I'm way off... but can anyone lead me in the right direction? How can I set this up on the controller-side?
You have to intercept the param in your controller and filter your results using the param.
def index
if params[:difficulty]
#questions = Question.where(difficulty: params[:difficulty])
else
#questions = Question.all
end
end
You can pass parameter depends on your condition
see the example
View:
<%= link_to "View", questions_path(:difficulty => 1) %>
note: you can send dynamic values to difficulty parameter
Controller:
def index
if params[:difficulty]
#questions = Question.all.where(:difficulty => params[:difficulty])
else
#questions = Question.all
end
end
routes.rb
resources :questions
You should provide a little more information, but maybe this will point you in the right direction if you are running a rails framework. I would create associations within the database objects so they can share certain characteristics. Check this out and see if this is what you're trying to do, http://guides.rubyonrails.org/association_basics.html . As for as the controller, that is where you'll define the method for calling the associations.

Rails will_paginate - how to make nicer route?

I have on the homepage list of articles that are listed with using will_paginate gem.
Everything works well, but there is one thing I would want to improve - on the homepage, the data are loaded into home controller and index action.
So, when I load my website - www.website.com, data are loaded into home/index. When I click on the pagination link for the second page, the link is www.website.com/home/index?page=2. I would like to see there in the best way www.website.com/page/2 (or www.website.com/?page=2).
Basically, the point is to remove from the URL /home/index - is there any way to do this?
Thanks
You may do it this way - add this class to some helper module, for example app/helpers/application_helper.rb:
module ApplicationHelper
class SmartLinkRenderer < WillPaginate::ActionView::LinkRenderer
protected
def link(text, target, attributes = {})
if target.is_a? Fixnum
attributes[:rel] = rel_value(target)
target = url(target)
end
attributes[:href] = target.gsub(/[?&]page=(\d+)/,'/page/\1')
tag(:a, text, attributes)
end
end
end
You may customize it according to your needs, for example do
attributes[:href] = target.gsub(/home\/index/,'')
or whatever. And then you may do this in your views:
<%= will_paginate #items, :renderer => 'ApplicationHelper::SmartLinkRenderer' %>
Try this
root to: 'home#index'
in you config/routes.rb file
EDIT
to be able to route these kind of requests:
www.website.com/page/2
add this to routes.rb:
match "page/:page" => "your_root_controller#index"
this way :page will be in your params hash.
and for example index method to view your Message model can be:
def index
#messages = Messages.paginate(page: params[:page])
end
hope that can help. for more information please refer to RoR routing

Passing (and using) parameters to the "new" action of a controller

My app has Lessons which have many Drills.
When I am looking at a lesson I want to be able to create new Drills and automatically assign their lesson_id.
So far what I have is a link in the lesson's show.html.erb that passes in the lesson's id, like so:
<%= link_to t('.new', :default => t("helpers.links.new")),
new_drill_path(lesson_id: #lesson.id), :class => 'btn' %>
This adds the lesson_id to the params hash. I figured out how to pass the param into the drill by doing this in my controller:
def new
#drill = Drill.new
params.each do |key, value|
method = key.to_s + '='
method.to_sym
if #drill.respond_to? method
#drill.send method, value
end
end
end
However, this code seems smelly to me. It seems like there ought to be a more rails-y way to do it, but I can't figure out what it is.
Use nested resources. Something like this:
# in config/routes.rb
resources :lessons do
resources :drills
end
That'll give you nested URLs/routes, and route helpers like lesson_drills_path that take a Lesson-record as its argument to produce a path like /lessons/:lesson_id/drills.
Your DrillsController will therefore have access to params[:lesson_id] because it'll be given in the URL. That means that you can do things like
# POST /lesson/:lesson_id/drills/
def create
#lesson = Lesson.find(params[:lesson_id])
#drill = #lesson.drills.new(params[:drill])
if #drill.save
..
else
..
end
end
See more in this answer over on CodeReview, and check the links in there too
I'm not exactly sure what you're trying to do, but read up on Nested Resources. Your new action should look something like:
def new
#lesson = Book.find(params[:lesson_id])
#drill = #lesson.drills.build
end

Resources