When I try to edit an instance of my Job model, the attributes I'm trying to update are set to Nil.
I've tried using the regular form_for helper instead of simple_form because I didn't know if simple_form required extra info such as what action and method to use, but it didn't work.
edit.html.erb
<h1>Edit Job:</h1>
<br>
<%= simple_form_for #job do |f| %>
<%= f.input :title, label: "Job title" %>
<%= f.input :description, label: "Description" %>
<%= f.button :submit %>
<% end %>
jobs_controller.rb
def edit
#job = Job.find(params[:id])
end
def update
#job = Job.find(params[:id])
#job.update(title: params[:title], description: params[:description])
if #job.save
redirect_to jobs_path(#job)
else
render "edit"
end
end
routes.rb
resources :candidates
resources :tenants, constraints: { subdomain: 'www' }, except: :index
resources :jobs, path_names: { new: 'add' }
get 'candidates/index'
get 'candidates/new/:id' => 'candidates#new', :as => 'apply'
get 'candidates/single/:id' => 'candidates#single', :as => 'view_candidate'
get 'jobs/single/:id' => 'jobs#single', :as => 'single_job'
get 'add-job' => 'jobs#new'
get 'listings' => 'jobs#listings', :as => 'career_page'
get 'listing/:id' => 'jobs#listing', :as => 'view_job'
get 'welcome/index', constraints: { subdomain: 'www' }
get 'dashboard' => 'tenants#dashboard', as: 'dashboard'
constraints SubdomainConstraint do
devise_for :users, path_names: { edit: 'account' }
root 'tenants#dashboard'
end
root 'welcome#index'
No error, but attributes are Nil, and URL is displayed instead of #job.title in the index view (because its Nil)
I believe the form data are wrapped into key :job in params so attributes for Job need to be whitelisted
def update
#job = Job.find(params[:id])
#job.update(job_params)
if #job.save
redirect_to jobs_path(#job)
else
render "edit"
end
end
Private
def job_params
params.require(:job).permit(:title, :description)
end
Related
I've created a contact form in Rails 4 with this example.
But I want to display this contact form on the main/show page of my application. How can I do this?
routes.rb.
Rails.application.routes.draw do
resources :projects
resources :contacts, only: [:new, :create]
get 'welcome/index'
root 'welcome#index'
end
contacts_controller.rb
class ContactsController < ApplicationController
def new
#contact = Contact.new
end
def create
#contact = Contact.new(params[:contact])
#contact.request = request
if #contact.deliver
flash.now[:error] = nil
else
flash.now[:error] = 'Cannot send message.'
render :new
end
end
end
Thanks.
And easy and clean way would be to create a partial
_contact_form.html.erb (Partials always starts with an underscore)
.container
%h1 Contact
= simple_form_for #contact, :html => {:class => 'form-horizontal' } do |f|
= f.input :name, :required => true
= f.input :email, :required => true
= f.input :message, :as => :text, :required => false, :input_html => {:rows => 10}
.hidden
= f.input :nickname, :hint => 'Leave this field blank!'
.form-actions
= f.button :submit, 'Send message', :class=> "btn btn-primary"
Then, in your index page:
<%= render "contacts/contact_form" %>
and in your controller index action( I don't know if 'welcome/index' is on project's controller or contacts controller)
def index
#your code
#contact = Contact.new
end
Finally, you seem quite new to rails, I'd like to recommend a free Ruby on Rails Tutorial
I have Photo model which belongs to User model. Rails returns this error whenever I try to access new view for /users/4/photos/new:
No route matches {:action=>"index", :controller=>"photos", :user_id=>"4"} missing required keys: [:id]
This is my PhotosController:
class PhotosController < ApplicationController
def index
find_user
#photos = #user.photos
end
def new
find_user
#photo = #user.photos.build
end
def show
find_photo
end
def create
#photo = Photo.new(params[:photo])
if #photo.save
if params[:images]
params[:images].each { |image|
#user.photos.create(image: image)
}
end
else
render 'new'
end
end
def update
find_user
#photo = #user.photos.find(params[:id])
if #photo.update
redirect_to photos_path
else
render 'edit'
end
end
def destroy
find_photo
#photo.destroy
redirect_to photos_path
end
private
def find_user
#user = User.find(params[:user_id])
end
def find_photo
#photo = Photo.find(params[:id])
end
def photo_params
require(:photo).permit(:title, :image, :user_id)
end
end
And this is my _form partial for photos views.
<%= form_for #photo, :html => { class: 'form-horizontal', multipart: true } do |f| %>
<%= f.label :title %>
<%= f.text_field :title, class: "input-field form-control" %>
<%= f.label :pictures %>
<%= file_field_tag "images[]", type: :file, multiplue: true %>
<%= f.submit nil, class: "btn btn-primary" %>
I don't understand how ID is missing, I'm providing it via find_user method.
Update:
# routes.rb
Rails.application.routes.draw do
root 'welcome#index'
# prevedene rute
get "/pocetna" => "welcome#index", as: "index"
get "/o-sajtu" => "welcome#about", as: "about"
get "/moj-profil" => "users#show", as: "profile"
post "/users" => "users#create"
get "/users" => "users#index", as: "users"
get "/user" => "users#index"
get "/users/:id" => "users#show", as: "user"
get "/users/:id/edit" => "users#edit", as: "edit_user"
patch "/users/:id" => "users#update"
get "/users/add" => "users#new", as: "new_user"
resources :sessions, only: [:new, :create, :destroy]
get "/login" => "sessions#new", as: "login"
post "/login" => "sessions#create"
get "/logout" => "sessions#destroy", as: "logout"
delete "/logout" => "sessions#destroy"
resources :users do
resources :photos
end
end
Update
I get new error now
undefined method `photos_path' for #<<Class:0x007f4f14f16160>:0x00000004f040e8>
First line of the form is marked.
change your form_for in _form partial to
form_for([#user, #photo]) do |f|
#rest of your code
end
How do you call the /users/4/photos/new in your view? Ideally you should pass the user_id as id not as user_id. Once, you do that this issue should be resolved.
So I'm trying to get the acts_as_commentable_with_threading gem working in my app. I would like to allow the users to comment on specific events (events/show.html). I don't think I've set it up properly as I'm getting the below error.
error:
Showing /Users/user/Sites/new_work/app/views/events/show.html.erb where line #36 raised:
First argument in form cannot contain nil or be empty
</div>
<div class="name"></div>
<div id="comments">
<%= form_for #comment do |f| %> <---- it's referring to this line
<div><%= f.hidden_field :event_id, value: #event.id %></div>
<div><%= f.text_field :body, row: 20, placeholder: "Leave a comment" %></div>
<%= f.submit "Post Comment" %>
comments_controller.rb
class CommentsController < ApplicationController
before_filter :load_commentable
def index
#comments = #commentable.current_user.comments
end
def new
#comment = #commentable.current_user.comments.new
end
def create
#comment = #commentable.current_user.comments.new(params[:comment])
if #comment.save
redirect_to #commentable, notice: "Comment created."
else
render :new
end
end
private
def load_commentable
resource, id = request.path.split('/')[1, 2]
#commentable = resource.singularize.classify.constantize.find(id)
end
end
comment.rb snippit only
class Comment < ActiveRecord::Base
attr_accessible :title, :body, :subject
acts_as_nested_set :scope => [:commentable_id, :commentable_type]
validates :body, :presence => true
validates :user, :presence => true
# NOTE: install the acts_as_votable plugin if you
# want user to vote on the quality of comments.
#acts_as_votable
belongs_to :commentable, :polymorphic => true
# NOTE: Comments belong to a user
belongs_to :user
event.rb
class Event < ActiveRecord::Base
attr_accessible :title, :description, :location, :date, :time, :event_date
acts_as_commentable
has_many :comments, as: :commentable
belongs_to :user
after_create :update_event_date
def update_event_date
date = self.date.to_s
time = self.time
hour = Time.parse(time).strftime("%H:%M:%S").to_s
event_date = (date + ' ' + hour).to_time
self.update_attributes(event_date: event_date)
end
end
comments/form.html.erb
<%= form_for [#commentable, #comment] do |f| %>
<% if #comment.errors.any? %>
<div class="error_messages">
<h3>Please correct the following errors.</h3>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
</ul>
</div>
<% end %>
<div class="field">
<%= f.text_field :body, rows: 10, placeholder: "Leave a comment" %>
</div>
<div class="actions">
<%= f.submit "Post comment", class: "btn" %>
</div>
<% end %>
events_controller.rb
class EventsController < ApplicationController
before_filter :authenticate_user!
def index
#user = current_user
#events = Event.all
end
def new
#event = Event.new
end
# def create
# #event = Event.new(params[:event])
# if #event.save
# redirect_to :action => 'index'
# else
# #events = Event.find(:all)
# render :action => 'new'
# end
# end
def create
#event = current_user.events.new(event_params)
respond_to do |format|
if #event.save
format.html { redirect_to :back, notice: 'Event was successfully created.' }
format.json { render action: 'show', status: :created, location: #event }
format.js
else
format.html { render action: 'new' }
format.json { render json: #event.errors, status: :unprocessable_entity }
format.js
end
end
end
def show
#event = Event.find(params[:id])
end
def edit
#event = Event.find(params[:id])
end
def update
#event = Event.find(params[:id])
if #event.update_attributes(params[:event])
flash[:success] = "Event updated."
redirect_to #event
else
render 'edit'
end
end
def destroy
#event = Event.find(params[:id])
#event.destroy
respond_to do |format|
format.html {redirect_to :back}
format.js
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_event
#event = Event.find(params[:id])
end
routes.rb
New_app::Application.routes.draw do
# get 'auth/:provider/callback', to: 'sessions#create'
# get 'auth/failure', to: redirect('/')
root to: "home#landing"
devise_for :users, :controllers => {:registrations => "users/registrations",
:sessions => "users/sessions",
:passwords => "users/passwords",
:omniauth_callbacks => "users/omniauth_callbacks"
}
get "welcome", to: "home#welcome", as: 'welcome'
devise_scope :user do
# get "edit/edit_account", :to => "devise/registrations#edit_account", :as => "account_registration"
get 'edit/edit_account' => 'users/registrations#account_registration', as: :edit_account
end
# patch '/users/:id', to: 'users#update', as: 'user'
get 'profile/:id' => "users#show", as: :profile
get 'disconnect' => 'users#disconnect'
resources :users do
resources :questions
end
resources :photos
resources :events do
resources :comments
end
post "/events/add_new_comment" => "events#add_new_comment", :as => "add_new_comment_to_events", :via => [:event]
resources :questions
end
rake routes for comments
event_comments GET /events/:event_id/comments(.:format) comments#index
POST /events/:event_id/comments(.:format) comments#create
new_event_comment GET /events/:event_id/comments/new(.:format) comments#new
edit_event_comment GET /events/:event_id/comments/:id/edit(.:format) comments#edit
event_comment GET /events/:event_id/comments/:id(.:format) comments#show
PATCH /events/:event_id/comments/:id(.:format) comments#update
PUT /events/:event_id/comments/:id(.:format) comments#update
DELETE /events/:event_id/comments/:id(.:format) comments#destroy
Is #comment defined in the "show" action in your Events controller? Can you post the Events controller code as well?
One thing to double check is to ensure that the action that renders the view for show.html.erb has the #comment variable defined. You seem to be getting the message because the #comment variable in
<%= form_for #comment do |f| %>
Is currently nil when you render the view.
In the "show" action for the events controller, try setting the #comment variable by adding:
#comment = #event.comments.new
Edit 2: Make sure you've setup your routes.rb file to handle comments on events, so assuming youre using RESTful routes, something like this below in your routes.rb. If you could post the routes file that would be helpful too.
resources :events do
resources :comments
end
The error is on app/views/events/show.html.erb which means that your Events controller's show action is missing the #comment variable
def show
#event = Event.find(params[:id])
#comment = ....what ever you need to pull in the comments....
end
When I call the delete action on my on my index.html.erb page for images, it references the correct id's and such, but it does not order them in the url correctly. The url should look like http://localhost:3000/admin/albums/33/images/1, but it displays as http://localhost:3000/admin/albums/33/images.1. I know it has something to do with the .:format, but I'm not sure how to fix it. When I put this in the delete action, admin_album_images_path([#album, image]), it results in http://localhost:3000/admin/albums/33/1/images.
routes
Admin::Application.routes.draw do
get "albums/index"
get "dashboard/index"
namespace :admin do
root :to => "dashboard#index"
resources :dashboard
resources :albums do
resources :images
end
get "admin/album"
end
get "logout" => "sessions#destroy", :as => "logout"
get "login" => "sessions#new", :as => "login"
get "signup" => "users#new", :as => "signup"
# resources :users
resources :basic
root :to => "basic#index"
Controller
class Admin::ImagesController < ApplicationController
def index
#album = Album.find(params[:album_id])
#image = #album.images(params[:id])
#images = Image.all
end
def new
#album = Album.find(params[:album_id])
#image = #album.images.new
end
def create
#album = Album.find(params[:album_id])
#image = #album.images.build(params[:image])
if #image.save
flash[:notice] = "Successfully added image!"
redirect_to [:admin, :albums]
else
render :action => 'new'
end
end
def show
#album = Album.find(params[:id])
#image = #album.images(params[:id])
end
def destroy
#album = Album.find(params[:album_id])
#image = #album.images(params[:id])
#image.destroy
redirect_to admin_albums_path
end
end
View
<% #images.each do |image|%>
<%= image.title %> </br>
<%= image.description %> </br>
<%= image.image_name %> </br>
<%= button_to "Delete", admin_album_images_path(#album, image), :method => :delete, :style => "display: block; float: left;" %>
<%= debug #image %>
<% end %>
you should use
admin_album_image_path(#album, image)
note that both are singular. you can also change that to [:admin, #album, image] so you don't have to worry about the name of the route
An additional parameter will by default become the format so
admin_album_image_path(#album, image, :csv)
will be converted to
/admin/albums/1/images/1.csv
I am using the Nested_Set gem in my code to sort Categories, Subcategories, and Products. I am trying to limit the depth/level of my nested set to no deeper then 2. Currently I am getting the error
Nested Set Error undefined method `self_and_descendants' for #<ActiveRecord::Relation:0x52c4a30>
I am trying to create a restraunt menu type style, and am going to attempt to make it drag and drop sortable.
Here is my code:
Can someone browse it and help me understand this error? Thanks
Category.rb
class Category < ActiveRecord::Base
acts_as_nested_set
acts_as_list :scope => :parent_id
has_many :products
scope :category, where("parent_id IS NULL")
scope :subcategories, where("parent_id IS NOT NULL")
scope :with_depth_below, lambda { |level| where(self.arel_table[:depth].lt(level)) }
end
categories_controller
class CategoriesController < ApplicationController
def new
#category = params[:id] ? Category.find(params[:id]).children.new : Category.new
#count = Category.count
end
def new_subcategory
#category = params[:id] ? Category.find(params[:id]).children.new : Category.new
#category_2_deep = Category.with_depth_below(2)
end
def create
#category = params[:id] ? Category.find(params[:id]).children.new(params[:category]) : Category.new(params[:category])
if #category.save
redirect_to products_path, :notice => "Category created! Woo Hoo!"
else
render "new"
end
end
def edit
#category = Category.find(params[:id])
end
def edit_subcategory
#category = Category.find(params[:id])
#category_2deep = Category.with_depth_below(2).arrange
end
def destroy
#category = Category.find(params[:id])
#category.destroy
flash[:notice] = "Category has been obliterated!"
redirect_to products_path
end
def update
#category = Category.find(params[:id])
if #category.update_attributes(params[:category])
flash[:notice] = "Changed it for ya!"
redirect_to products_path
else
flash[:alert] = "Category has not been updated."
render :action => "edit"
end
end
def show
#category = Category.find(params[:id])
end
def index
end
def sort
params[:category].each_with_index do |id, index|
Category.update_all({position: index+1}, {id: id})
end
end
end
Routes.rb
Jensenlocksmithing::Application.routes.draw do
get "log_out" => "sessions#destroy", as: "log_out"
get "log_in" => "sessions#new", as: "log_in"
get "site/home"
get "site/about_us"
get "site/faq"
get "site/discounts"
get "site/services"
get "site/contact_us"
get "site/admin"
get "site/posts"
get "categories/new_subcategory"
get "categories/edit_subcategory"
resources :users
resources :sessions
resources :coupons
resources :monthly_posts
resources :categories do
collection { post :sort }
resources :children, :controller => :categories, :only => [:index, :new, :create, :new_subcategory]
end
resources :subcategories
resources :products
resources :reviews
resources :faqs do
collection { post :sort }
end
root to: 'site#home'
end
categories/form.html.erb
<%= form_for(#category) do |f| %>
<p>
<%= f.label(:name) %>
<%= f.text_field :name %>
</p>
<p>
<%= f.label(:parent_id) %>
<%= f.select :parent_id, nested_set_options(#category_2_deep, #category) {|i, level| "# {'-' * level if level < 1 } #{i.name if level < 1 }" } %>
</p>
<p>
<%= f.label(:position) %>
<%= f.select :position, 1..category_count %>
</p>
<p>
<%= f.submit("Submit") %>
</p>
<% end %>
It looks like nested_set is looking for an Array not just an array-like collection - see line 32 of the source: https://github.com/skyeagle/nested_set/blob/21a009aec86911f5581147dd22de3c5d086355bb/lib/nested_set/helper.rb#L32
...hence it's getting that ActiveRecord::Relation, wrapping it in an [array] (line 35) and then trying to iterate and blowing up.
Easy fix: call to_a on the collection first - in your controller:
#category_2_deep = Category.with_depth_below(2).to_a
Better fix: submit a patch to the maintainer that's a bit more Ruby-like and looks for it to behave like an Array, but not necessarily be one.