fields_for not saving nested parameters in rails 5.0.1 - nested

I'm fairly new to rails, though I've made some basic apps and read several tutorials, this is the first time I've delved into nested attributes inside forms and the use of fields_for.
I've searched trough many similar questions and have read the documentation on fields_for, however my form doesn't seem to save whenever I use fields_for inside my form. I've tested without the fields_for and saves as it should (without saving to the nested DB, obviously).
What I'm trying to do is a simple Event registration, which in turn has some attributes and a date in a separate model.
I've tried with and without validations, many different things inside the strong parameters
Here is my Event models:
class Event < ApplicationRecord
has_many :eventdates, dependent: :destroy
accepts_nested_attributes_for :eventdates
validates :name, :description, :city, :street, :postal_code, presence: true
end
The Eventdate model:
class Eventdate < ApplicationRecord
belongs_to :event
validates :date, :start_hour, :finish_hour, :event_id, presence: true
end
The Event controller:
class EventsController < ApplicationController
def new
#event = Event.new
#event.eventdates.build
end
def create
#event = Event.new(event_params)
if #event.save
redirect_to root_url
else
render "static_pages/home"
end
end
private
def event_params
params.require(:event).permit(:name, :description, :street, :city, :postal_code, :address_number, :additional_info,
eventdates_attributes: [:id, :date, :start_hour, :finish_hour, :event_id])
end
And the form:
<%= form_for(#event, url: events_path) do |f| %>
<p>
<%= f.label :nombre %>
<%= f.text_field :name %>
</p>
<div>
<%= f.fields_for :eventdates do |eventdate_fields| %>
<%= eventdate_fields.label :fecha %>
<%= eventdate_fields.date_field :date %>
<%= eventdate_fields.label :hora_de_inicio %>
<%= eventdate_fields.time_field :start_hour %>
<%= eventdate_fields.label :hora_de_termino %>
<%= eventdate_fields.time_field :finish_hour %>
<% end %>
</div>
<p>
<%= f.label :infomación_adicional %>
<%= f.text_area :additional_info %>
</p>
<p>
<%= f.submit "Crear evento" %>
</p>
<% end %>
I'm pretty sure this is a very simple form, but somehow refuses to save at all into the database.

In eventdate.rb model, append optional: true to this line: belongs_to :event
class Eventdate < ApplicationRecord
belongs_to :event, optional: true
validates :date, :start_hour, :finish_hour, :event_id, presence: true
end
Because Rails will create eventdates first, then create event and links to those evendates (by updating all event_id in these evendates). But when creating eventdates, column event_id is nil and eventdates cannot be saved.

Related

wrong number of arguments (0 for 1..2) Rails 4.2.0 and Ruby 2.2.2

I'm trying to embedded mail_form into my home page.
The 'contacts#new' is rendered on 'static_pages#home' so I instantiate #contact in StaticPagesController's home action to avoid the "First argument in form cannot contain nil or be empty" error.
But I now I get wrong number of arguments (0 for 1..2) errors instead.
I see this behaviour since I updated my ruby to 2.2.2.
Do you think this error is caused by new specification on Ruby, or it is just my simple code error?
static_pages_controller
class StaticPagesController < ApplicationController
def home
#contact = Contact.new
end
end
views/static_pages/home.html.erb
<section id="contact">
<%= render template: 'contacts/new' %>
</section>
contacts_controller
class ContactsController < ApplicationController
def new
#contact = Contact.new
end
def create
#contact = Contact.new(contact_params)
#contact.request = request
if #contact.deliver
flash.now[:notice] = "Thank you for your message. We will contact you soon!"
else
flash.now[:error] = "Cannot send message."
render 'new'
end
end
private
def contact_params
params.require(:contact).permit(:name, :email, :message)
end
end
views/contacts/new.html.erb
<%= form_for(#contact) do |f| %>
...
<% end %>
Logs
Processing by StaticPagesController#home as HTML
Rendered contacts/new.html.erb (23.5ms)
Rendered static_pages/home.html.erb within layouts/application (238.2ms)
Completed 500 Internal Server Error in 278ms
ArgumentError (wrong number of arguments (0 for 1..2)):
app/views/contacts/new.html.erb:28:in `block in_app_views_contacts_new_html_erb___4238619170782302276_70113984753480'
I update my version of 'byebug' to '4.0.1' and 'Web-console' to '2.1.2', then it shows where was the error. It was actually really stupid ...
Error:
<%= form_for(#contact) do |f| %>
<%= t.email_field ... %>
...
<% end %>
Correct:
<%= form_for(#contact) do |f| %>
<%= f.email_field ... %>
...
<% end %>

Searching Multiple Models with Ransack Rails 4

I'm trying to figure out how to search multiple models with Ransack. The goal is to have the search form in my shared header. I'm using a combination of their documentation, an old rails-cast, SO questions, and some code a friend shared with me. Right now I think it works, although I'm not sure because I can't get the results to show on my index page.
First, I created a search controller:
class SearchController < ApplicationController
def index
q = params[:q]
#items = Item.search(name_cont: q).result
#booths = Booth.search(name_cont: q).result
#users = User.search(name_cont: q).result
end
end
Next, I put this code in the header partial (views/layouts/_header.html.erb):
<%= form_tag search_path, method: :get do %>
<%= text_field_tag :q, nil %>
<% end %>
I added a route:
get "search" => "search#index"
My index.html.erb for the Search controller is empty and I suspect that is the problem, but I'm not sure what to place there. When I try something like:
<%= #items %>
<%= #users %>
<%= #booths %>
This is the output I get when I execute a search:
#<Item::ActiveRecord_Relation:0x007fee61a1ba10> #<User::ActiveRecord_Relation:0x007fee61a32d28> #<Booth::ActiveRecord_Relation:0x007fee61a20790>
Can someone please guide me on what the solution might be? I'm not sure if it's an index view problem, routing problem, or something else. On all of the tutorials the search field and results are only for one model so I'm a little confused on how to pull this off across multiple models.
Thanks!
The output you are getting is correct. Each of those variables contains an ActiveRecord_Relation object which can be treated like an array. Normally you'd do something like:
<% #items.each do |item| %>
<%= item.name %> # or whatever
<% end %>
<% #users.each do |user| %>
# and so on
Alternatively, you could combine your results #results = #items + #booths + #users and then:
<% #results.each do |result| %>
# display the result
<% end %>

where to put :html => { :multipart => true } in form_for & fields_for?

I have a form_for that has a fields_for for a double object form creation. The second object is attachments that has a paperclip (ruby gem) attribute for adding photos attributed to the first object. The box model is being created, but the attachment model is not as far as I can tell. One of my questions is where the multipart => true needs to go, the form_for, fields_for, or both?
Edit: it seems that the box_id cannot be passed through as a param because the box hasn't been created yet. So how do I make the attachment attributed to the box in the controller? I thought
#box.attachments.build(params)
would make the correct attribution, but that doesn't work.
Do I need to user nested attributes here?
Here is the console log:
Processing by BoxesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0vka+nZDc56OdISMctWoJjY8CH+TR20PHBl8oVglD5A=", "box"=>{"user_id"=>"45", "name"=>"asdfasdf", "origin"=>"asdfasdf", "description"=>"asdfasdf"}, "attachment"=>{"box_id"=>"", "screen_shot"=>#<ActionDispatch::Http::UploadedFile:0x007fc3d8202990 #tempfile=#<Tempfile:/tmp/RackMultipart20140521-11119-37nj3s>, #original_filename="P5110017.JPG", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"attachment[screen_shot]\"; filename=\"P5110017.JPG\"\r\nContent-Type: image/jpeg\r\n">}, "commit"=>"Share the Love!"}
Note that the box_id is blank, yet with the validation in the model I don't get any errors.
Here is my form code:
<%= form_for #box, :html => { :multipart => true } do |f| %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.label :name, "Name" %><br>
<%= f.text_field :name, autofocus: true %><br>
<%= f.label :origin, 'Website' %><br>
<%= f.text_field :origin %><br>
<%= f.label :description %><br>
<%= f.text_area :description, cols: "30", rows: "4" %>
<%= fields_for #attachment do |ff| %>
<%= ff.hidden_field :box_id, :value => #box.id %>
<%= ff.file_field :screen_shot, id:"attachment", :required => true %>
<% end %>
<%= f.submit "Create!" %>
<% end %>
Here is my controller:
class BoxesController < ApplicationController
def new
#box = Box.new
#attachment = Attachment.new
end
def create
#box = current_user.boxes.build(boxes_params)
#attachment = #box.attachments.build(attachment_params)
if #box.save
flash[:success] = "Box created"
redirect_to #box
else
flash[:error] = "There was an error"
redirect_to 'new'
end
end
def update
#box = Box.find(params[:id])
if #box.update_attributes(boxes_params)
flash[:success] = "Box updated"
redirect_to #box
else
render 'edit'
end
end
def destroy
#box = Box.find(params[:id])
#box.destroy
flash[:success] = "Box deleted."
redirect_to root_url
end
private
def boxes_params
params.require(:box).permit(:description, :name, :origin, :attachment)
end
def attachment_params
params.require(:attachment).permit(:screen_shot, :box_id)
end
end
And the box model:
class Box < ActiveRecord::Base
belongs_to :user
has_many :comments
has_many :attachments, :dependent => :destroy, :limit => 4
is_impressionable
validate :attachments_count_within_limit, :on => :create
validates :user_id, presence: true
validates_presence_of :name
validates_length_of :description, :maximum => 1000
Attachment model:
class Attachment < ActiveRecord::Base
belongs_to :box
has_attached_file :screen_shot, :styles => { :medium => "300x300>", :thumb => "100x100>" }
validates_attachment_content_type :screen_shot, :content_type => /\Aimage\/.*\Z/
validates :box_id, presence: true
end
I had also tried changing the box_controller to create the attachment via
#attachment = Attachment.new(attachment_params)
but that still did not work.
Try printing out #box.id in your view and see if it contains the required id and also send your box_id along with :screenshot
def attachment_params
params.require(:attachment).permit(:box_id, :screen_shot)
end

search with Mongoid on Rails 4 not only on string fields but also on date ranges

parent.rb
class Parent
include Mongoid::Document
field :name, type: String
field :hobby, type: String
field :born, type: Date
embeds_many :children
accepts_nested_attributes_for :children
end
children.rb
class Child
include Mongoid::Document
field :hobby, type: String
field :name, type: String
field :born, type: Date
embedded_in :parent
end
parents_controller.rb
class ParentsController < ApplicationController
before_action :set_parent, only: [:show, :edit, :update, :destroy]
# GET /parents
# GET /parents.json
def index
#parents = Parent.all
end
# GET /parents/1
# GET /parents/1.json
def show
end
# GET /parents/new
def new
#parent = Parent.new
end
# GET /parents/1/edit
def edit
end
# POST /parents
# POST /parents.json
def create
#parent = Parent.new(parent_params)
respond_to do |format|
if #parent.save
format.html { redirect_to #parent, notice: 'Parent was successfully created.' }
format.json { render action: 'show', status: :created, location: #parent }
else
format.html { render action: 'new' }
format.json { render json: #parent.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /parents/1
# PATCH/PUT /parents/1.json
def update
respond_to do |format|
if #parent.update_attributes(parent_params)
format.html { redirect_to #parent, notice: 'Parent was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #parent.errors, status: :unprocessable_entity }
end
end
end
# DELETE /parents/1
# DELETE /parents/1.json
def destroy
#parent.destroy
respond_to do |format|
format.html { redirect_to parents_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_parent
#parent = Parent.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def parent_params
params.require(:parent).permit(:name, :hobby, :born)
end
end
Parents' index.html.erb:
<h1>Listing parents</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Born</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<% #parents.each do |parent| %>
<tr>
<td><%= parent.name %></td>
<td><%= parent.born %></td>
<td><%= link_to 'Show', parent %></td>
<td><%= link_to 'Edit', edit_parent_path(parent) %></td>
<td><%= link_to 'Destroy', parent, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Parent', new_parent_path %>
I want to implement a search feature to search not only in the main document but in the nested as well. Search not only in text fields, but also with date ranges. Can anyone point me any resource (tutorial) regarding this? I couldn't find anything like Ryan's Simple Search railscast.
I'd very obliged if someone could show me how I will have to modify my controllers and index.html.erb files.
There's also a Durran's page related to search in the github https://github.com/mongoid/mongoid/blob/master/lib/mongoid/contextual/text_search.rb. But frankly speaking it didn't give any clue to solve my issue.
You'll want for example to have your index method taking a search param
def index
#parents = if params[:search]
Parent.where(name: params[:search])
else
Parent.all
end
end
This is the basic idea. You may consider having a class method for doing more complex search (using born attributes for example).
def index
if params[:search]
#parents = Parent.search_for(params[:search])
else
#parents = Parent.all
end
end
In your model:
class Parent
def search_for(criterias)
# Logic regarding criterias selection should go here.
# Very basic idea bellow
Parent.where(name: criterias[:name], born: criterias[:born])
end
end
In your view:
// First case
<%= text_field_tag :search, '' %>
// Second case
<%= text_field_tag 'search[name]', '' %>
<%= text_field_tag 'search[born]', '' %>
Thanks to #Pierre-Louis Gottfrois for advice that helped me do some further research.
I became able to search on two fields (name and hobby) as follows.
I've added onto the product's index.html.erb:
<%= form_tag parents_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
Then in the parent.rb model I changed taking into account #Pierre-Louis Gottfrois's advice :
def self.search(search)
if search
any_of({name: search}, {hobby: search})
end
end
products_controller.rb changed:
def index
if params[:search].empty?
#parents = Parent.all
else
#parents = Parent.search(params[:search])
end
end
There're 3 problems still exist and I thought it would be better split them in different posts:
How to ignore case-sensitiveness while searching
How to search including nested documents
Ability to search by specifying date ranges
Consider any word as a result if it contains a search-keyword

Rails ActiveAdmin Layout was lost after overriding Controller action

Overriding a new controller without 'new!' does not display ActiveAdmin layout. But then when I added 'new!' nested 'synchronization' form is not appearing although I did '#resource.build_synchronization'. Not so sure what I'm doing wrong here.
case #1 (ActiveAdmin layout is gone)
ActiveAdmin.register Resource do
controller do
# This code is evaluated within the controller class
def new
#resource = Resource.new
#resource.build_synchronization
end
end
end
case #2 (nested form synchronization does not appear)
ActiveAdmin.register Resource do
controller do
# This code is evaluated within the controller class
def new
#resource = Resource.new
#resource.build_synchronization
new!
end
end
end
views\admin\resources\new.html.erb
<%= semantic_form_for [:admin, #resource] do |form| %>
<%= form.inputs "Resource", :id => "resource" do %>
<%= form.input :name %>
<%= form.semantic_fields_for :synchronization do |sync| %>
<% sync.inputs :name => "Synchronization", :id => "synchronization" do %>
<%= sync.input :start_datetime, :as => :datetime %>
<%= sync.input :repeat_interval, :as => :radio, :collection => #intervals %>
<%= sync.input :repeat_type, :as => :select, :collection => ["Manual", "Automatic"] %>
<% end %>
<% end %>
<% end %>
<%= form.buttons %>
<% end %>
<% end %>
models:
class Resource < ActiveRecord::Base
has_one :synchronization
accepts_nested_attributes_for :synchronization
end
class Synchronization < ActiveRecord::Base
belongs_to :resource
has_many :mappings
accepts_nested_attributes_for :mappings
#validates_presence_of :start_datetime
end
For CRUD actions active admin don't use standart layout
lib/active_admin/resource_controller.rb
# Determine which layout to use.
#
# 1. If we're rendering a standard Active Admin action, we want layout(false)
# because these actions are subclasses of the Base page (which implementes
# all the required layout code)
# 2. If we're rendering a custom action, we'll use the active_admin layout so
# that users can render any template inside Active Admin.
def determine_active_admin_layout
ACTIVE_ADMIN_ACTIONS.include?(params[:action].to_sym) ? false : 'active_admin'
end
You can define layout manually
controller do
layout 'active_admin', :only => [:new]
end
You need to put the form.semantic_fields_for statement inside a form.inputs block.
Also, I would not put form.buttons inside neither the form.semantic_fields_for block nor a form.inputs block. It should be a direct child under the semantic_form_for block (this is not what is causing your problem, but just the location where you would normally put this).

Resources