Pass another data than the id in the URL - ruby-on-rails

I'm currently creating a website that would allow a visitor to read a magazine online. I created a scaffold for the magazine itself, and another one for the pages, which belongs to the magazine. This way, I can create a multi upload for the pages while creating the magazine, and everything gets uploaded in the same time.
When I nest the pages resources inside the magazine's resources, as following:
resources :magazines do
resources :pages
end
I get "domain.com/magazines/<slug>/pages/id"
However, I had some issues with the id, because it can't be used to count the pages (since the id never goes back to 1), so I created a function inside the controller that would count the pages for me, and save each pages with a "page_number" value.
My question is the following: how, instead of the id, can I kindly ask my router to use the :page_number ?
I tried to create a custom route, which looked like this
resources :magazines do
get '/:page_number' => 'pages#show', as: :custom_page
end
But for an unknown reason, Rails tells me that my custom route simply doesn't exist, even though it exists when I type rake routes
Thank you in advance
Edit
Here is my magazine_controller.rb
class MagazinesController < ApplicationController
before_action :authenticate_user!, only: [:edit, :update, :destroy]
before_action :set_magazine, only: [:show, :edit, :update, :destroy]
def index
#magazines = Magazine.all
end
def show
end
def new
#magazine = Magazine.new
end
def edit
end
def create
#magazine = Magazine.new(magazine_params)
if #magazine.save
if params[:images]
(params[:image] || []).each_with_index do |image, index|
#magazine.pages.create(image: image, page_number: index + 1)
end
redirect_to #magazine, notice: 'Magazine was successfully created.'
else
render :new
end
end
end
def update
if #magazine.update(magazine_params)
if params[:images]
params[:images].each { |image|
#magazine.pages.create(image: image)
}
end
redirect_to #magazine, notice: 'Magazine was successfully updated.'
else
render :edit
end
end
def destroy
#magazine.destroy
redirect_to magazines_url, notice: 'Magazine was successfully destroyed.'
end
private
def set_magazine
#magazine = Magazine.friendly.find(params[:id])
end
def magazine_params
params.require(:magazine).permit(:titre, :apercu)
end
end
and here is page_controller.rb
class PagesController < ApplicationController
before_action :authenticate_user!, only: [:edit, :update, :destroy]
before_action :set_page, only: [:show, :edit, :update, :destroy]
def index
#pages = Page.all
end
def show
end
def new
#page = Page.new
end
def edit
end
def create
#page = Page.new(page_params)
if #page.save
redirect_to #page, notice: 'Page was successfully created.'
else
render :new
end
end
def update
if #page.update(page_params)
redirect_to #page, notice: 'Page was successfully updated.'
else
render :edit
end
end
def destroy
#page.destroy
redirect_to :back, notice: 'Page was successfully destroyed.'
end
private
def set_page
#page = Page.find(params[:id])
end
def page_params
params.require(:page).permit(:titre, :apercu)
end
end
Edit 2
Here is the output from development.log when trying to reach the page
Started GET "/magazines/magazine-54/pages/11" for 127.0.0.1 at 2016-12-12 11:04:45 +0100
Processing by PagesController#show as HTML
Parameters: {"magazine_id"=>"magazine-54", "id"=>"11"}
Completed 500 Internal Server Error in 2ms (ActiveRecord: 0.0ms)
NoMethodError (undefined method `pages' for nil:NilClass):
app/controllers/pages_controller.rb:49:in `set_page'
Rendering /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout
Rendering /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_source.html.erb
Rendered /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_source.html.erb (2.4ms)
Rendering /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
Rendered /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (1.2ms)
Rendering /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
Rendered /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (0.7ms)
Rendered /var/lib/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (13.8ms)

With these routes
resources :magazines do
resources :pages
end
you should be able to update PagesController and add/update following methods:
def magazine
#magazine = Magazine.find(params[:magazine_id])
end
def page
#page = #magazine.pages.find_by(page_number: params[:id])
end
to make it work you should have page_number column in Page model and has_many :pages association in Magazine model

Related

Filtering out other users's notes in Searchkick rails 5

I'm a beginner to Ruby on Rails working on a Notebook app. I'm trying using Searchkick to enable users to quickly search their notes. I currently have 2 users (via devise gem).
I have just set up Searchkick, but when I search for a word that both the users have in their notes, the result shows notes by both users. So, a user can see the other's note in this case as in the image below.
Here is my notes_controller.rb code:
class NotesController < ApplicationController
before_action :find_note, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#notes = Note.where(user_id: current_user).order("created_at DESC")
end
def search
if params[:search].present?
#notes = Note.search(params[:search])
else
#notes = Note.all
end
end
def new
#note = current_user.notes.build
end
def create
#note = current_user.notes.build(note_params)
if #note.save
redirect_to root_path, notice: "Note successfully created."
else
render 'new'
end
end
def show
end
def edit
end
def update
if #note.update(note_params)
redirect_to note_path(#note), notice: "Note successfully updated."
else
render 'edit'
end
end
def destroy
#note.destroy
redirect_to root_path, notice: "Note successfully deleted."
end
private
def note_params
params.require(:note).permit(:title, :body)
end
def find_note
#note = Note.find(params[:id])
end
end
My routes.rb code:
Rails.application.routes.draw do
devise_for :users
resources :notes do
collection do
get :search
end
end
authenticated :user do
root "notes#index"
end
root "welcome#home"
end
My search.html.erb code, which is the same as index.html.erb code:
<% #notes.each do |note| %>
<h2><%= link_to note.title, note_path(note) %></h2>
<% end %>
I have a feeling I need to add a conditional statement in the search action in the notes_controller but that is not working.
Can anyone help please?
Thank you.
That would be
#notes = Note.search params[:search], where: { user_id: current_user.id }

How can I create a Rails search bar facility without using additional gems

I am building a small classifieds application for our community where folks can list products for sale using a form with params description and image only.
Both params are in the schema.rb
THE PROBLEM:
I have embedded the search bar on my index.html.erb and also created a show.html.erb which is blank. Currently the search bar does nothing except look pretty,
I am struggling to understand how to get the search wired up to interrogate the description param and deliver the results onto my show.html.erb.
NB: I would like the show.html.erb page and its search results to mirror my index page cosmetically and achieve this task without having to install any further gems.
class PinsController < ApplicationController
before_action :set_pin, only: [:show, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#pins = Pin.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 15)
end
def show
end
def new
#pin = current_user.pins.build
end
def edit
end
def create
#pin = current_user.pins.build(pin_params)
if #pin.save
redirect_to #pin, notice: 'Pin was successfully created.'
else
render :new
end
end
def update
if #pin.update(pin_params)
redirect_to #pin, notice: 'Pin was successfully updated.'
else
render :edit
end
end
def destroy
#pin.destroy
redirect_to pins_url
end
private
# Use callbacks to share common setup or constraints between actions.
def set_pin
#pin = Pin.find_by(id: params[:id])
end
def correct_user
#pin = current_user.pins.find_by(id: params[:id])
redirect_to pins_path, notice: "Not authorized to edit this pin" if #pin.nil?
end
# Never trust parameters from the scary internet, only allow the white list through.
def pin_params
params.require(:pin).permit(:description, :image)
end
end
Change your index method to either have a search query or not.
def index
if params[:query]
#results = Advert.where('lower(description) LIKE ?', '%#{params[:query].downcase}%')
else
#results = Advert.all
end
end
You can also create filters using javascript or install either searchkick gem or if you need something REALLY simple install rails4-autocomplete

Rails 4 controller News generated by scaffold not working properly

I searched about this question, but had no success.
I´m trying to learn ruby on rails, came from php. I generated a webapp with the generation tool, second I generated a News controller with scaffold. The devise and pundit are installed too with gems.
The program works perfectly, the problem is related to the News module, I generated it with scaffold.
The routes where created with the command: resources :news
My idea is to create one _form.html.erb and it be called to create a new record or to updated an existing record. Some tutorials teach to create a new.html.erb and an update.html.erb file and duplicate the code, but I know that is possible to have partials as the main form part.
I´m using simple_form_for and the code to do the new is:
# GET /news/new
def new
#news = New.new
authorize New
end
The _form.html.erb
<%= simple_form_for(#news) do |f| %>
<%= f.input :titulo %>
<%= f.input :resumo %>
<%= f.button :submit %>
<% end %>
When I enter to edit, it works, but to add a new it throws.
ActionController::UrlGenerationError at /news/new
No route matches {:action=>"show", :controller=>"news", :locale=>:en} missing required keys: [:id]
Sorry for my bad english, I´m without direction here, is there any way that I can solve it?
Thanks.
====== UPDATED =======
routes.rb
Rails.application.routes.draw do
root to: 'visitors#index'
devise_for :users
resources :users
resources :news
end
New.rb (Model)
class New < ActiveRecord::Base
belongs_to :user
end
application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :set_locale
def default_url_options(options={})
{ locale: I18n.locale }
end
private
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
end
news_controller.rb (Complete)
class NewsController < ApplicationController
before_filter :authenticate_user!
after_action :verify_authorized
#before_action :set_news, only: [:show, :edit, :update, :destroy]
# GET /news
# GET /news.json
def index
#news = New.all
authorize New
end
# GET /news/1
# GET /news/1.json
def show
#news = New.find(params[:id])
authorize New
end
# GET /news/new
def new
#news = New.new
authorize New
end
# GET /news/1/edit
def edit
#news = New.find(params[:id])
authorize New
end
# POST /news
# POST /news.json
def create
#news = New.new(news_params)
respond_to do |format|
if #news.save
format.html { redirect_to #news, notice: 'New was successfully created.' }
format.json { render :show, status: :created, location: #news }
else
format.html { render :new }
format.json { render json: #news.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /news/1
# PATCH/PUT /news/1.json
def update
respond_to do |format|
if #news.update(news_params)
format.html { redirect_to #news, notice: 'New was successfully updated.' }
format.json { render :show, status: :ok, location: #news }
else
format.html { render :edit }
format.json { render json: #news.errors, status: :unprocessable_entity }
end
end
end
# DELETE /news/1
# DELETE /news/1.json
def destroy
#news.destroy
respond_to do |format|
format.html { redirect_to news_url, notice: 'New was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_news
#news = New.find(params[:id])
end
private
def news_params
params.require(:news).permit(:titulo, :resumo, :texto, :published_at, :user_id)
end
end
Command rake routes
news_index GET /news(.:format) news#index
POST /news(.:format) news#create
new_news GET /news/new(.:format) news#new
edit_news GET /news/:id/edit(.:format) news#edit
news GET /news/:id(.:format) news#show
PATCH /news/:id(.:format) news#update
PUT /news/:id(.:format) news#update
DELETE /news/:id(.:format) news#destroy
Thanks in advance.
======= UPDATE 2 ===========
Changing my New action to this:
def new
#news = New.create(params[:id])
end
It solved, but everytime I enter, it creates an empty record...
Use news_index_path for GET /news and POST /news. Rails doesn't figure out the pluralization correctly for the "news" term.
Check the output of rake routes, it will be obvious.

Couldn't find User with 'id'=

I know this is the most commonly asked question but i am really looking for some help here as i don't understand what i am doing wrong here .
I have a generated a devise user and intend to create a gallery for users . Following is the code i have tried
Model - Gallery.rb
class Gallery < ActiveRecord::Base
belongs_to :user
end
Controller - galleries_controller.rb
class GalleriesController < ApplicationController
before_action :set_gallery, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!
respond_to :html
def index
#user = User.find(params[:user_id])
#galleries = Gallery.all
respond_with(#galleries)
end
def show
respond_with(#gallery)
end
def new
#user = User.find(params[:user_id])
#gallery = Gallery.new
respond_with(#gallery)
end
def edit
end
def create
#gallery = Gallery.new(gallery_params)
flash[:notice] = 'Gallery was successfully created.' if #gallery.save
respond_with(#gallery)
end
def update
flash[:notice] = 'Gallery was successfully updated.' if #gallery.update(gallery_params)
respond_with(#gallery)
end
def destroy
#gallery.destroy
respond_with(#gallery)
end
private
def set_gallery
#gallery = Gallery.find(params[:id])
end
def gallery_params
params[:gallery, :user_id]
end
end
Folowing is the error that gets shown with better errors -
Logs
Started GET "/galleries/1" for 127.0.0.1 at 2015-05-03 15:24:10 +0530
Processing by GalleriesController#show as HTML
Parameters: {"id"=>"1"}
Gallery Load (2.1ms) SELECT "galleries".* FROM "galleries" WHERE "galleries"."id" = ? LIMIT 1 [["id", 1]]
Completed 404 Not Found in 63ms
ActiveRecord::RecordNotFound - Couldn't find Gallery with 'id'=1:
activerecord (4.2.0) lib/active_record/core.rb:154:in `find'
routes.rb
Rails.application.routes.draw do
root to: 'visitors#index'
devise_for :users
resources :users do
resources :galleries
resources :photos
end
end
As i am still new to ROR , any help would be very much appreciated . Thanks in advance .
From the URL i am assuming you are not passing user_id in params.
In your route file gallery should be nested route. If you wan't user_id.
resources :users do
resources :galleries do
end
end
or you can use
#user= current_user

Rails 4: One-to-one controller issue

I'm building an app which consists on sharing résumés. I am using Devise gem. Each user is able to create only one résumé. I made the models and and their relations. Resume belongs_to User and User has_one 'Resume'.
After making the views, I wanted to test my app but I got the error: undefined methodbuild' for nil:NilClass`
Here is my ResumeController and my routes.rb
class ResumeController < ApplicationController
before_action :find_resume, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:show]
def show
# #resume = Resume.find_by(params[:id])
end
def new
#resume = current_user.resume.build
end
def create
#resume = current_user.resume.build(resume_params)
if #resume.save
redirect_to #resume, notice: "resume was successfully created"
else
render 'new'
end
end
def edit
end
def update
if #resume.update(pin_params)
redirect_to #resume, notice: "resume was successfully updated"
else
render 'edit'
end
end
def destroy
#resume.destroy
redirect_to root_path
end
private
def resume_params
params.require(:resume).permit(:title, :description)
end
def find_resume
#resume = resume.find(params[:id])
end
end
Routes.rb
Rails.application.routes.draw do
devise_for :users
resources :resume, except: [:index]
get 'static_pages/index'
root to: "static_pages#index"
end
I just want the user to be able to create only one Resume and then he will be able to share it.
Update: After following messanjah's answer there was another error coming from the _form.html.erb: undefined method resumes_path' for #<#<Class:0x00...>. Here is the gist with forms and model: goo.gl/XvW2LH So you can see all the files closely.
Without more knowledge of where the error is happening, I can only suggest some areas that might be suspect.
To build a has_one relationship, you must use the build_*association* constructor.
def new
#resume = current_user.build_resume
end
def create
#resume = current_user.build_resume(resume_params)
end

Resources