Nesting resource - ruby-on-rails

I'm trying to nest my messages controller into my channels controller. But when I go to my messages view i get the error "couldn't find channel with no id"
class MessagesController < ApplicationController
def index
#channel = Channel.find(params[:channel_id])
#messages = #channel.messages
end
def new
#channel = Channel.find(params[:channel_id])
#message = #channel.messages.build
end
def create
#channel = Channel.find(params[:channel_id])
#message = #channel.messages.build(params[:message])
if #message.save
flash[:notice] = "Successfully created message."
redirect_to channel_url(#message.channel_id)
else
render :action => 'new'
end
end
def edit
#message = Message.find(params[:id])
end
def update
#message = Message.find(params[:id])
if #message.update_attributes(params[:message])
flash[:notice] = "Successfully updated message."
redirect_to channel_url(#message.channel_id)
else
render :action => 'edit'
end
end
def destroy
#message = Message.find(params[:id])
#message.destroy
flash[:notice] = "Successfully destroyed message."
redirect_to channel_url(#message.channel_id)
end
end
Channels controller
class ChannelsController < ApplicationController
def index
#channels = Channel.find(:all)
end
def show
#channel = Channel.find(params[:id])
#message = Message.new(:channel => #channel)
end
def new
#channel = Channel.new
end
def create
#channel = Channel.new(params[:channel])
if #channel.save
flash[:notice] = "Successfully created channel."
redirect_to #channel
else
render :action => 'new'
end
end
def edit
#channel = Channel.find(params[:id])
end
def update
#channel = Channel.find(params[:id])
if #channel.update_attributes(params[:channel])
flash[:notice] = "Successfully updated channel."
redirect_to #channel
else
render :action => 'edit'
end
end
def destroy
#channel = Channel.find(params[:id])
#channel.destroy
flash[:notice] = "Successfully destroyed channel."
redirect_to channels_url
end
end
routes.rb
SeniorProject::Application.routes.draw do
resources :users
resources :channels, :shallow => true do |channels|
channels.resources :messages
end
root :channels
resources :users, :user_sessions
match 'login' => 'user_sessions#new', :as => :login
match 'logout' => 'user_sessions#destroy', :as => :logout
match ':controller(/:action(/:id(.:format)))'
end

What's going on here is that this line:
#channel = Channel.find(params[:channel_id])
Is falling over because there's no defined channel_id in the params hash. I see you're using shallow routes, which means your uri probably looks like this:
/messages
And you need it to look like:
/channels/1/messages
Try changing your url to be:
channel_messages_url(#channel)
instead of
messages_url
This is a guess btw, it could be because of the way you've defined your routes.rb, which looks a little odd because you're defining the messages routes twice, once with the has_many and again as a proper resource. You probably want something like:
# assuming you need shallow routes
resources :channels, :shallow => true do |channels|
channels.resources :messages
end

Related

the foreign key is just passing to the new form not the create action (ruby on rails)

This is my controllers and routes
I have a albums controller and a bands controler with their models, and I want to access the foreign key to pass it, but it told me bands is blank
def show
#album = Album.find_by(:id => params[:id])
render :show
end
def new
#band = Band.find_by(:id => params[:band_id])
#albums = Album.new(:band_id => params[:band_id])
render :new
end
def create
#albums = Album.new(albums_params)
if #albums.save
flash[:success] = "Album created successfully"
redirect_to album_path(#albums.id)
else
#band = #albums.band
flash[:error] = #albums.errors.full_messages
render :new
end
end
def update
render :edit
end
def edit
end
def destroy
end
private
def albums_params
params.require(:albums).permit(:name, :band_id, :live, :year)
end
end```
resources :bands do
resources :albums, :only => :new
end
Try to pass Band relation like below.
def new
#band = Band.find_by(:id => params[:band_id])
#albums = Album.new(:band => #band)
render :new
end
OR check your code. Can you find Band with correct id?
#band = Band.find_by(:id => params[:band_id])
AND check your Views
You must put someting like below
<%=form.hidden_field :band_id, value: #albums.band_id%>
OR
<%=form.hidden_field :band_id, value: #band.id %>

Couldn't find Item with 'id'. Paper trail issue, unable to undo action

My To-do list application, I want to be able to undo changes.
If the task(item) is completed or deleted, I have an undo hyperlink to revert the change.
I am using the paper trail gem file.
The URL is http://localhost:3000/versions/315/revert
Looks like it is not reverting back and picking the item, to revert the change.
I have the versions controller with fi statements that if the Item is blank, return record not found. As it is not returning the message it must have something?
I don't know what I am doing wrong here, any help would be greatly appreciated.
Here is my main Task (item) controller.rb
class ItemsController < ApplicationController
before_action :find_item, only: [:show, :edit, :update, :destroy]
def index
if user_signed_in?
#items = Item.where(:user_id => current_user.id).order("created_at DESC")
end
end
def show
end
def new
#item = current_user.items.build
end
def create
#item = current_user.items.build(item_params)
if #item.save
redirect_to root_path, :notice => "Congrats! Task was created!"
else
render 'new'
end
end
def edit
end
def update
if #item.update(item_params)
redirect_to item_path(#item), :notice => "Congrats! Task was updated!"
else
render 'edit'
end
end
def destroy
#item.destroy
redirect_to root_path , :notice => "Task was Deleted! To Revert click. #{undo_link}"
end
def complete
#item = Item.find(params[:id])
#item.update_attribute(:completed_at, Time.now)
redirect_to root_path , :notice => "To undo completed task please click. #{undo_link}"
end
private
def item_params
params.require(:item).permit(:title, :description)
end
def find_item
#item = Item.find(params[:id])
end
def undo_link
view_context.link_to("undo",revert_version_path(#item.versions.scope.last), :method => :post)
end
end
Here is the versions controller
class VersionsController < ApplicationController
PaperTrail::Version.where('created_at < ?', 1.day.ago).delete_all
def revert
#item = Item.find(params[:id])
if #item.blank?
format.html {redirect_to(rooth_path, :notice => 'Record not found') }
elsif #item.reify
#item.reify.save!
else
#item.item.destroy
end
link_name = params[:redo] == "true" ? "undo" : "redo"
link = view_context.link_to(link_name, revert_version_path(#item.next, :redo => !params[:redo]), :method => :post)
redirect_to :back, :notice => "Undid #{#item.event}. #{link}"
end
end
Here is my Item model (tasks)
class Item < ActiveRecord::Base
belongs_to :user
has_paper_trail # you can pass various options here
def completed?
!completed_at.blank?
end
end
Here is my routes folder
Rails.application.routes.draw do
post "versions/:id/revert" => "versions#revert", :as => "revert_version"
devise_for :users
resources :items do
member do
patch :complete
end
end
root 'items#index'
get '/about' => 'page#about'
end

How to pass parameters when building an Object in Rails controller

I have an Event model and a Notifications model. An event has many notifications, and a notification only has one event. My notification object has two attributes: message and event_id. When I build a new notification, how can I set the event_id to the current event's id?
events_controller.rb
class EventsController < ApplicationController
before_action :signed_in, only: [:new,:create]
def new
#event = Event.new
end
def create
#event = Event.new(event_params)
if #event.save
flash[:success] = "Your Event has been created."
redirect_to root_path
else
render 'new'
end
end
def show
#event = Event.find(params[:id])
#notification = #event.notifications.build
respond_to do |format|
format.html
format.xml { render :xml => #event }
format.json { render :json => #event }
end
end
private
def event_params
params.require(:event).permit(:name, :description)
end
def signed_in
unless user_signed_in?
redirect_to new_user_session_path
flash[:warning] = "You must be signed in to access that page"
end
end
end
notifications_controller.rb
class NotificationsController < ApplicationController
def create
#notification = Notification.new(notification_params)
if #notification.save
redirect_to root_path
flash[:success] = "Your message has been sent"
else
render 'new'
end
end
def show
end
private
def notification_params
params.require(:notification).permit(:message, :event_id)
end
def signed_in
unless user_signed_in?
redirect_to new_user_session_path
flash[:warning] = "You must be signed in to access that page"
end
end
end
routes.rb
devise_for :users
resources :events
resources :notifications
root 'static_pages#home'
match '/help', to: 'static_pages#help', via: 'get'
match '/about', to: 'static_pages#about', via: 'get'
match '/contact', to: 'static_pages#contact', via: 'get'
#notification = #event.build_notification(notification_params)

Allow users to upload photos bypassing creating gallery

I have a social network and for it I am using carrier wave. I need help with setting it up so that users do not have to create a Gallery name to upload photos. That's the default setup for carrierwave, but since this is a social network I am not allowing users to have different Galleries (or albums). There should only be a link to upload photos to their profile. So how should I attack this? BTW I am new to Rails so any and all help would be greatly appreciated!
photos controller:
def new
#photo = Photo.new(:gallery_id => params[:gallery_id])
end
def create
#photo = Photo.new(params[:photo])
if #photo.save
flash[:notice] = "Successfully created photos."
redirect_to #photo.gallery
else
render :action => 'new'
end
end
def edit
#photo = Photo.find(params[:id])
end
def update
#photo = Photo.find(params[:id])
if #photo.update_attributes(paramas[:photo])
flash[:notice] = "Successfully updated photo."
redirect_to #photo.gallery
else
render :action => 'edit'
end
end
def destroy
#photo = Photo.find(params[:id])
#photo.destroy
flash[:notice] = "Successfully destroyed photo."
redirect_to #photo.gallery
end
end
galleries controller:
def index
#galleries = Gallery.all
end
def show
#gallery = Gallery.find(params[:id])
end
def new
#gallery = Gallery.new
end
def create
#gallery = Gallery.new(params[:gallery])
if #gallery.save
flash[:notice] = "Successfully created gallery."
redirect_to #gallery
else
render :action => 'new'
end
end
def edit
#gallery = Gallery.find(params[:id])
end
def update
#gallery = Gallery.find(params[:id])
if #gallery.update_attributes(params[:gallery])
flash[:notice] = "Successfully updated gallery."
redirect_to gallery_url
else
render :action => 'edit'
end
end
def destroy
#gallery = Gallery.find(params[:id])
#gallery.destroy
flash[:notice] = "Successfully destroy gallery."
redirect_to galleries_url
end
end
routes:
Dating::Application.routes.draw do
get 'signup' => 'users#new'
get 'login' => 'sessions#new'
get 'logout' => 'sessions#destroy'
get 'edit' => 'users#edit'
get "/profile/:id" => "users#show"
get "profile/:id/settings" => 'users#edit'
match 'settings/:id' => 'users#settings'
resources :users
resources :sessions
resources :password_resets
resources :galleries
resources :photos
resources :searches
resources :users do
get 'settings', on: :member
end
root to: 'users#new'
root to: 'galleries#index'
resources :users do |user|
resources :messages do
collection do
post 'delete_multiple'
end
end
end
zwippie s answer is a good option as far as I can see.
If you follow zwippie´s answer, you have to modify your photos controller, e.g like follwoing:
def new
#photo = Photo.new
end
def create
#photo = Photo.new(params[:photo])
#photo.gallery = current_user.gallery
if #photo.save
flash[:notice] = "Successfully created photos."
redirect_to gallery_path #photo.gallery
else
render :action => 'new'
end
end
An completely other option is not to generate any gallery, just associate the current user to the photo.
user model:
class User < ActiveRecord::Base
has_many :photos
end
class Photos < ActiveRecord::Base
belongs_to :user
end
photos_controller
def new
#photo = Photo.new
end
def create
#photo = Photo.new(params[:photo])
#photo.user = current_user
if #photo.save
flash[:notice] = "Successfully created photos."
redirect_to user_photos_path(current_user)
else
render :action => 'new'
end
end
As gallery name for your carrierwave setup you can for example choose the current user username, or something else.
UPDATE: changed redirect path
your routes should look like following:
resources :users do
resources :photos
end
Why not create the gallery directly after the user has signed up? Or create it when the user uploads the first picture.
photos_controller:
def new
# Get the gallery for the current user (assuming Gallery has attribute user_id)
#gallery = current_user.gallery
# Create a new gallery if user does not have one already
#gallery = Gallery.create(:user_id => current_user.id) if #gallery.nil?
# Save the photo
#photo = Photo.new(:gallery_id => #gallery.id)
end
You can use paperClip to create photoalbum, here is link for paperclip gem:
https://github.com/thoughtbot/paperclip

Railscast Login Remember me

i followed the revised railcast and then decided to upgrade my code with a remember feature. Almost work but When going to the login page I get the following error
Couldn't find Customer with auth_token =
Note I change the table from User to Customer
Here my code, maybe i made a little mistake. I did a reset on the database
Customer Controller
class CustomersController < ApplicationController
def new
#customer = Customer.new
end
def create
#customer = Customer.new(params[:customer])
if #customer.save
session[:customer_id] = #customer.id
redirect_to root_url, notice: "Thank you for signing up!"
else
render "new"
end
end
end
Session Controller
class SessionsController < ApplicationController
def new
end
def create
customer = Customer.find_by_email(params[:email])
if customer && customer.authenticate(params[:password])
if params[:remember_me]
cookies.permanent[:auth_token] = customer.auth_token
else
cookies[:auth_token] = customer.auth_token
end
redirect_to root_url, :notice => "Logged in!"
else
flash.now.alert = "Invalid email or password"
render "new"
end
end
def destroy
cookies.delete(:auth_token)
redirect_to root_url, :notice => "Logged out!"
end
end
Route.rb
get 'signup', to: 'customers#new', as: 'signup'
get 'login', to: 'sessions#new', as: 'login'
get 'logout', to: 'sessions#destroy', as: 'logout'
resources :sessions
resources :customers
root :to => 'sessions#new'
Application Controller
class ApplicationController < ActionController::Base
protect_from_forgery
private
def authorize
redirect_to login_url, alert: "Not authorized" if current_customer.nil?
end
def current_customer
#current_customer ||= Customer.find_by_auth_token!(cookies[:auth_token]) if cookies[:auth_token]
end
helper_method :current_customer
end
Thanks everyone
My mistake was in the following code
def current_customer
#current_customer ||= Customer.find_by_auth_token!(cookies[:auth_token]) if cookies[:auth_token]
end
and fixing it by the following
def current_customer
#current_customer ||= Customer.find_by_auth_token(cookies[:auth_token]) if cookies[:auth_token]
end

Resources