Ruby on Rails won't render edit page without id - ruby-on-rails

For some reason the edit action won't render i get this error and is using show action instead of edit but the same form works for the render :new action
do not focus on the params[:preview], i am talking about the last render :edit
ActionController::UrlGenerationError in Admin::Blog::Posts#update
No route matches {:action=>"show", :controller=>"admin/blog/posts", :id=>""} missing required keys: [:id]
def edit
#post = Post.find_by_permalink(params[:id])
end
def update
#post = Post.find_by_permalink(params[:id])
if params[:publish]
#post.publish
elsif params[:draft]
#post.draft
end
if params[:preview]
if #post.published?
#post.draft
end
if #post.update(blog_post_params)
flash[:success] = "some text "
redirect_to blog_post_url(#post)
else
render :edit
end
end
if #post.update(blog_post_params)
flash[:success] = "Post was successfully updated."
redirect_to edit_admin_blog_post_url(#post)
else
render :edit
end
end
form
<%= form_for [:admin,:blog, #post] do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="large-12 columns">
<div class="field panel">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field panel">
<%= f.label :description %><br>
<%= f.text_field :description %>
</div>
<div class="actions panel text-right">
<% if #post.published? %>
<%= f.submit "Save Changes",name: "publish", class: "tiny button radius success" %>
<% else %>
<%= f.submit "Publish",name: "publish", class: "tiny button radius success" %>
<% end %>
<%= f.submit 'Mark as Draft', name: "draft", class: "tiny button radius " %>
<% if #post.created_at %>
<%= f.submit 'Preview', name: "preview", class: "tiny button radius warning" %>
<% end %>
<%= link_to 'Back', admin_blog_posts_path, class: "tiny button radius secondary" %>
</div>
<div class="field panel">
<%= f.label :body %><br>
<%= f.cktext_area :body, :height => '800px', :id => 'sometext' %>
</div>
</div>
<% end %>
relevant routes
namespace :admin do
namespace :blog do
get '', to: 'welcome#index', as: '/'
resources :posts
end
end
post model
class Post < ActiveRecord::Base
has_many :tags
has_many :comments
before_validation :generate_permalink
validates :permalink, uniqueness: true
validates :title, presence: true
validates :description, presence: true
def generate_permalink
self.permalink = title.parameterize
end
def to_param
permalink
end
end

I guess i know why you get this error.
In the edit action you use Post.find_by_permalink(params[:id]) to find your post, which returns nil if nothing was found. And since you may change the title attribute, your permalink is updated (i guess), and your post is not found. The controller still renders the action, with nil #post, and cannot generate the url for the form.
Try using Post.find_by_permalink!(params[:id]) instead, and you will get a 404.
I would actually suggest you to use regular find in the admin area, since the permalink might change.

Related

has_many join form with collection checkboxes not saving more than one checkbox value

I am working on a form for a editorial calendar app. I have two things going out that are pretty similar and not working.
Working with 3 models: Platforms, Posts and Calendars. They are join tables. Platform <=> Post, Post <=> Calendars
Post/new & Post/edit form:
<div class="container">
<div class="form-field">
<%= form_for #post do |f| %>
<%= f.label :title %>
<%= f.text_field :title, required: true %> <br>
Title is required.
</div>
<div class="form-field">
<%= f.label :content%>
<%= f.text_area :content%>
</div>
<div class="form-field">
<%= f.label :link %>
<%= f.text_field :link %>
</div>
<div class="file-field">
<%= f.label :picture%>
<%= f.file_field :picture, id: :post_picture%>
</div>
<div class="file-field">
<%= f.label :finalized %>
<%= f.radio_button :finalized , true%>
<%= f.label :finalized, "Yes" %>
<%= f.radio_button :finalized, false %>
<%= f.label :finalized, "No" %>
</div>
<%= f.hidden_field :user_id %> <br>
<div class="form-field">
<%= f.fields_for :platform_attributes do |platform| %>
<%= platform.label :platform, "Social Platforms"%>
<%= platform.collection_check_boxes :platform_ids, Platform.all, :id, :name %> <br> <br>
</div>
<div>
<h4> Or Create a new platform: </h4>
<%= platform.label :platform, 'New Platform'%>
<%= platform.text_field :name%> <br> <br>
</div>
<% end %>
<%= f.submit%>
<% end %>
</div>
My post controller is handling the checkboxes issue, and the "schedule post" issue. It will only allow me to schedule for one calendar, and it does not save the updates and add additional calendars.
Posts Controller:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :schedule_post, :destroy]
def new
#posts = current_user.posts.select {|p| p.persisted?}
#post = current_user.posts.build
#platforms = Platform.all
end
def edit
#calendars = current_user.calendars
#platforms = Platform.all
end
def create
#post = current_user.posts.build(post_params)
if #post.save
redirect_to post_path(#post)
else
redirect_to new_post_path
end
end
def update
#post.update(post_params)
if #post.save
redirect_to post_path(#post), notice: 'Your post has been updated.'
else
redirect_to edit_post_path(#post)
end
end
def schedule_post
#calendar_post = CalendarPost.new(calendar_post_params)
if #calendar_post.save
binding.pry
redirect_to post_path(#post)
else
render 'show'
end
end
private
def set_post
#post = Post.find(params[:id])
end
def set_calendars
#calendars = current_user.calendars
end
def post_params
params.require(:post).permit(:title, :content, :link, :finalized, :picture, :user_id, :platform_attributes => [:platform_ids, :name])
end
def calendar_post_params
params.require(:calendar_post).permit(:post_id, :calendar_id, :date, :time)
end
end
I want the user to be able to add a post to multiple platforms and multiple calendars because of the versatility of what someone may need.
I also have my setter in my Post model.
class Post < ApplicationRecord
has_many :calendar_posts
has_many :calendars, through: :calendar_posts
has_many :platform_posts
has_many :platforms, through: :platform_posts
belongs_to :user
def platform_attributes=(platform_attributes)
if platform_attributes['platform_ids']
platform_attributes.platform_ids.each do |id|
platform = Platform.find(id: id)
self.platforms << platform
end
end
if platform_attributes['name'] != ""
platform = Platform.find_or_create_by(name: platform_attributes['name'])
self.platforms << platform
end
end
thoughts? why are they not saving to more than one calendar or more than one platform if they choose to have more than one?
Here is the updated code... and more of what I know about these changes and what is happening.
My submit button is not working for some odd reason on my form, so I'm trying to get the params submitted but it won't even route to give me params even if I raise them, nothing is happening.
On the form you can choose checkboxes or add in a platform. If you add in a platform it creates that one but it does not also save the other ones you selected. If you go to edit the post, and click submit with changes, no page loads at all and nothing is happening in log. It's just idle.
<%= f.fields_for :platform_attributes do |platform| %>
assumes you are creating one platform... it says "these are the fields for this platform"
but platform_ids is intended to be a selection of a set of platforms... and probably should be outside of the fields_for section (which should only surround the name field).
try something like the following:
<div class="form-field">
<%= f.label :platform_ids, "Social Platforms"%>
<%= f.collection_check_boxes :platform_ids, Platform.all, :id, :name %> <br> <br>
</div>
<div>
<%= f.fields_for :platform_attributes do |platform| %>
<h4> Or Create a new platform: </h4>
<%= platform.label :name, 'New Platform'%>
<%= platform.text_field :name%> <br> <br>
<% end %>
<%# end fields_for %>
</div>
Also you'll need to update permit/require appropriately eg
def post_params
params.require(:post).permit(:title, :content, :link, :finalized, :picture, :user_id, :platform_ids, :platform_attributes => [:name])
end
Note: not tested - bugs are left as an exercise for the reader ;)

DRY controller .valid? for create and update using simple_form

So I've got these views:
new.html.erb
<div class="booyah-box col-xs-10 col-xs-offset-1">
<h1>Expose Your Hidden Gem</h1>
<%= simple_form_for #place do |f| %>
<%= f.input :name, error: "Name is mandatory" %>
<%= f.input :address %>
<%= f.input :description %>
<br />
<%= f.submit 'Create', class: 'btn btn-primary' %>
<% end %>
</div>
edit.html.erb
<div class="booyah-box col-xs-10 col-xs-offset-1">
<h1>Edit Your Place</h1>
<%= simple_form_for #place do |f| %>
<%= f.input :name %>
<%= f.input :address %>
<%= f.input :description %>
<br />
<%= f.submit 'Update', class: 'btn btn-primary' %>
<% end %>
</div>
this model:
Place.rb
class Place < ActiveRecord::Base
belongs_to :user
has_many :comments, dependent: :destroy
has_many :photos
geocoded_by :address
after_validation :geocode
validates :name, presence: true
validates :address, presence: true
validates :description, presence: true
end
And finally, places_controller.rb (only showing create and update)
def create
#place = current_user.places.create(place_params)
if #place.save
redirect_to root_path
else
render :new
end
end
def update
#place = Place.find(params[:id])
if #place.user != current_user
return render text: 'Not Allowed', status: :forbidden
end
#place.update_attributes(place_params)
if #place.save
redirect_to root_path
else
render :edit
end
end
But, I'm trying to think DRY and want to know if there is a better way to do a validation for name address and description presence without having the same identical code in both the create and update portions of my controller? I feel like I should just be writing it once...
First, you can refactor your views to use the following structure:
# new.html.erb
<div class="booyah-box col-xs-10 col-xs-offset-1">
<h1>Expose Your Hidden Gem</h1>
<%= render 'form' %>
</div>
# edit.html.erb
<div class="booyah-box col-xs-10 col-xs-offset-1">
<h1>Edit Your Place</h1>
<%= render 'form' %>
</div>
# _form.html.erb
<%= simple_form_for #place do |f| %>
<%= f.input :name %>
<%= f.input :address %>
<%= f.input :description %>
<br />
<% submit_label = #place.new_record? ? 'Create' : 'Update' %>
<%= f.submit submit_label, class: 'btn btn-primary' %>
<% end %>
And then in your controllers you could refactor to:
def create
#place = current_user.places.new(place_params)
if #place.save
redirect_to root_path
else
render :new
end
end
def update
#place = current_user.places.find(params[:id])
#place.attributes = place_params
if #place.save
redirect_to root_path
else
render :edit
end
end

Rails 4 Permitted Params with nested attributes

Alright, been looking everywhere for this one. Tried all the solutions. Maybe someone can help on this.
So, I have a WebRequest model that has many WebSites. Each WebSite belongs to a WebRequest. My problem is in the nested form. Ive gone in an permitted the params (atleast, based on the documentation I have) and everything works fine until I go into the server logs. Posted below
class WebRequest < ActiveRecord::Base
has_many :web_sites
accepts_nested_attributes_for :web_sites
end
and here is the WebSite model
class WebSite < ActiveRecord::Base
belongs_to :web_request, dependent: :destroy
end
_form.html.erb
<% 1.times do %>
<%= f.fields_for :web_site do |ff| %>
<%= ff.input :url %>
<%= ff.input :description %>
<% end %>
<% end %>
WebRequests Controller
class WebRequestsController < ApplicationController
def new
#web_request = WebRequest.new
# #web_request.web_sites.build
end
def index
#web_requests = WebRequest.all
end
def create
#web_request = WebRequest.new(web_request_params)
respond_to do |format|
if #web_request.save
RequestMailer.web_request_submit(#web_request).deliver
format.html { render partial: 'success' }
format.json { render action: 'show', status: :created, location: #web_request }
else
format.html { render action: 'new' }
format.json { render json: #web_request.errors, status: :unprocessable_entity }
end
end
end
def web_request_params
params.require(:web_request).permit(:web_needs, :primary_goal, :secondary_goal, : :call_to_action, :hero_image, :image_count, :existing, :resources, :web_examples, :special_functions, :social_network, web_sites_attributes: [:id, :url, :description])
end
end
And here is the server log:
Started POST "/web_requests" for 127.0.0.1 at 2014-07-10 15:56:12 -0400
Processing by WebRequestsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0iisNgGk/AhC4jRrp1cmKWVCBsCcSx5G2dueEI/+p2A=", "web_request"=>{"web_needs"=>"", "primary_goal"=>"", "secondary_goal"=>"", "call_to_action"=>"", "hero_image"=>"", "image_count"=>"", "existing"=>"", "web_site"=>{"url"=>"TROLL", "description"=>"TROLL"}, "resources"=>"", "special_functions"=>"", "social_network"=>""}, "commit"=>"Create Web request"}
Unpermitted parameters: web_site
Notice at how the form fields get passed but they get restricted out of making it to the DB.
THANKS!
Update::
Here is the full form path:
<%= simple_form_for(#web_request) do |f| %>
<% if #web_request.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#web_request.errors.count, "error") %>
prohibited this Web Request from being saved:</h2>
<ul>
<% #web_request.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="container">
<div class="field">
<%= f.input :web_needs, label: 'What web needs do you have?' %>
</div>
<div class="container"><h5>Please list below 5 URL's and explanations of why you like them.</h5></div>
<% 1.times do %>
<%= f.fields_for :web_sites do |ff| %>
<div class="field">
<%= ff.input :url, label: "URL of example site" %>
</div>
<div class="field">
<%= ff.input :description, label: "Description of example site" %>
</div>
<% end %>
<% end %>
<div class="field">
<%= f.input :resources, label: 'Will you be providing any kind of resource on this page? e.g. chord chart download.' %></br>
</div>
</div>
<div class="actions">
<%= f.button :submit, :class => "button" %>
</div>
</div>
<% end %>
Update::Full error log
undefined method `url' for #<ActiveRecord::Associations::CollectionProxy []>
The line is here
<% 1.times do %>
<%= f.simple_fields_for :web_site, #web_request.web_sites do |ff| %>
<div class="field">
<%= ff.input :url, label: "URL of example site" %> <--ERROR HERE on ':url'
</div>
<div class="field">
<%= ff.input :description, label: "Description of example site" %>
</div>
<% end %>
Add to controller in new action:
def new
#web_request = WebRequest.new
#web_site = #web_request.web_sites.build
end
and form:
<%= f.simple_fields_for #web_site do |ff| %>
<%= ff.input :url %>
<%= ff.input :description %>
<% end %>
<% end %>
and web_request_params:
def web_request_params
params.require(:web_request).permit(:web_needs,
:primary_goal,
:secondary_goal,
:call_to_action,
:hero_image,
:image_count,
:existing,
:resources,
:web_examples,
:special_functions,
:social_network,
{ web_sites: [:id, :url, :description] })
end
In your controller in web_request_params change web_sites_attributes for web_site_attributes
In your controller remove the comment from #web_request.web_sites.build
In your view remove 1.times do
In yor form change f.fields_for :web_sites do |ff| with f.simple_fields_for :web_sites do |ff|

unable to create or update a belongs_to record in Rails 4

I'm new to Rails and struggling to get my belongs_to association right. I have an app where a painting belongs to an artist and an artist can have_many paintings. I can create and edit my paintings, however I can not edit or create artists except through the console. Through much Googling I feel I have got myself turned around. Any help would be much appreciated!
Here's my routes.rb file:
MuseumApp::Application.routes.draw do
resources :paintings
resources :paintings do
resources :artists
resources :museums
end
root 'paintings#index'
end
Here's my paintings Controller
def show
#painting = Painting.find params[:id]
end
def new
#painting = Painting.new
##artist = Artist.new
end
def create
safe_painting_params = params.require(:painting).permit(:title, :image)
#painting = Painting.new safe_painting_params
if #painting.save
redirect_to #painting
else
render :new
end
end
def destroy
#painting = Painting.find(params[:id])
#painting.destroy
redirect_to action: :index
end
def edit
#painting = Painting.find(params[:id])
end
def update
#painting = Painting.find(params[:id])
if #painting.update_attributes(params[:painting].permit(:title, :image)) #safe_params
redirect_to #painting
else
render :edit
end
end
Here's the form in my paintings view:
<%= form_for(#painting) do |f| %>
<fieldset>
<legend>painting</legend>
<div>
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div>
<%= f.label :image %>
<%= f.text_field :image %>
</div>
<%= form_for([#painting,#painting.create_artist]) do |f| %>
<div>
<%= f.label :Artist %>
<%= f.text_field :name %>
</div>
</fieldset>
<%= f.submit %>
<% end %>
<% end %>
Artists Controller:
class ArtistsController < ApplicationController
def index
#artists = Artist.all
#artists = params[:q] ? Artist.search_for(params[:q]) : Artist.all
end
def show
#artist = Artist.find params[:id]
end
def new
#artist = Artist.new
end
def create
#painting = Painting.find(params[:painting_id])
#artist = #painting.create_artist(artist_params)
redirect_to painting_path(#painting)
end
def destroy
#artist = Artist.find(params[:id])
#Artist.destroy
redirect_to action: :index
end
def edit
#artist = Artist.find(params[:id])
end
def update
#painting = Painting.find(params[:painting_id])
#artist = #artist.update_attributes(artist_params)
redirect_to painting_path(#painting)
end
end
private
def artist_params
params.require(:artist).permit(:name)
end
Index view:
<h1> Hello and Welcome to Museum App</h1>
<h3><%= link_to "+ Add To Your Collection", new_painting_artist_path %></h3>
<%= form_tag '/', method: :get do %>
<%= search_field_tag :q, params[:q] %>
<%= submit_tag "Search" %>
<% end %>
<br>
<div id="paintings">
<ul>
<% #paintings.each do |painting| %>
<li><%= link_to painting.title, {action: :show, id:painting.id} %> by <%= painting.artist_name %></li>
<div id = "img">
<br><%= link_to (image_tag painting.image), painting.image %><br>
</div>
<%= link_to "Edit", edit_painting_path(id: painting.id) %>
||
<%= link_to 'Destroy', {action: :destroy, id: painting.id},method: :delete, data: {confirm: 'Are you sure?'} %>
<% end %>
</ul>
</div>
In your case you should use accepts_nested_attributes_for and fields_for to achieve this.
Artist
has_many :paintings, :dependent => :destroy
accepts_nested_attributes_for :paintings
Painting
belongs_to :artist
And also you should try creating artist with paintings like this
form_for(#artist) do |f| %>
<fieldset>
<legend>Artist</legend>
<%= f.label :Artist %>
<%= f.text_field :name %>
<%= fields_for :paintings, #artist.paintings do |artist_paintings| %>
<%= artist_paintings.label :title %>
<%= artist_paintings.text_field :title %>
<%= artist_paintings.label :image %>
<%= artsist_paintings.text_field :image %>
</fieldset>
<%= f.submit %>
<% end %>
Note:
You should be having your Artist Controller with at least new,create,edit and update methods defined in it to achieve this.
Edit
Try the reverse
Artist
has_many :paintings, :dependent => :destroy
Painting
belongs_to :artist
accepts_nested_attributes_for :paintings
form_for(#painting) do |f| %>
<fieldset>
<legend>Painting</legend>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :image %>
<%= f.text_field :image %>
<%= fields_for :artists, #painting.artists do |ff| %>
<%= ff.label :Artist %>
<%= ff.text_field :name %>
</fieldset>
<%= f.submit %>
<% end %>
Put this form in paintings views.

Rails 4 custom controller action error - "Couldn't find 'model' without an ID"

I'm trying to add a custom create action for my Book model, but i keep ending up with a "Couldn't find Book without an ID".
routes.rb:
Books::Application.routes.draw do
resources :books
resources :books do
collection do
post 'create_new_record', :action => :create_new_record
end
end
match 'create_new_record' => 'books#create_new_record', via: [:post]
The relevant controller action:
def create_new_record
#book = Book.new(book_params)
respond_to do |format|
if #book.save
format.html { redirect_to #book, notice: 'New book record created.' }
end
end
end
And my form (in new.html.erb). I'm looping through results that i get from goodreads.com.
<% #book_search.results.work.each do |stuff| %>
<%= form_for(#book, :url => create_new_record_books_path) do |f| %>
<div class="field">
<%= f.label :author %><br>
<%= f.text_field :author, :value => stuff.best_book.author.name %>
</div>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title, :value => stuff.best_book.title %>
</div>
<div class="field">
<%= f.label :isbn %><br>
<%= f.text_field :isbn, :value => stuff.best_book.isbn %>
</div>
<div class="field">
<%= f.label :image %><br>
<%= f.text_field :image, :value => stuff.best_book.image_url %>
</div>
<div class="field">
<%= f.label :bookid %><br>
<%= f.text_field :bookid, :value => stuff.best_book.id %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<hr>
<% end %>
The error i get when submitting the form is:
ActiveRecord::RecordNotFound in BooksController#create_new_record
on the callback
def set_book
#book = Book.find(params[:id])
end
I'm pretty much stumped now, my understanding is that it doesn't even reach the action, but instead looks for a book id that doesn't exist?
Thank you!
If you use before_filter so you don't pass an id to create action. Call your before filter the following way:
before_filter :set_book, except: [:index, :new, :create]
If you use model callback, params is unavailable in the model so pass the id some other way, for example via attr_accessor.
use #book = Book.where(id: params[:id]).first

Resources