make checkboxes for a has_many :through association using Formtastic - activeadmin

I have this models :
Offer
class Offer < ActiveRecord::Base
has_many :lists
has_many :documents
end
List
class List < ActiveRecord::Base
belongs_to :user
belongs_to :offer
has_many :entries, :dependent => :destroy
accepts_nested_attributes_for :entries, :allow_destroy => true
end
Entry
class Entry < ActiveRecord::Base
belongs_to :list
belongs_to :document
end
User
class User < ActiveRecord::Base
has_many :lists, :dependent => :destroy
end
I'm using ActiveAdmin, before my change I had this form for List :
form do |f|
f.inputs "Détails Utilisateurs" do
f.input :user
end
f.inputs "Accès" do
f.has_many :entries, {:title => '', :link => 'Ajouter un document'} do |c|
c.inputs '' do
if not c.object.id.nil?
c.input :_destroy, :as => :boolean, :label => "Supprimer l'accès"
end
c.input :document, :include_blank => false, :collection => offer.documents, :member_label => :to_label
end
end
end
f.buttons
end
But now I want to use checkbox instead of add/remove link buttons so I do something more like this :
form do |f|
f.inputs "Détails Utilisateurs" do
f.input :user
end
f.inputs "Accès" do
f.input :entries, :as => :check_boxes, :collection => offer.documents
end
f.buttons
end
But I havn't the correct name in checkbox, I have try with :name params and :html_options but they have no effect.
Any idea to fix this ?

Could you try with this?
form do |f|
f.inputs "Détails Utilisateurs" do
f.input :user
end
f.inputs "Accès" do
offer.documents.each do |document|
f.input document,
label: document,
as: :boolean do
f.check_box document, {}, "true", "false"
end
end
end
f.buttons
end
Hope it helps!

Related

Rails two nested attributes, "comments" on "posts" and on "issues" Not Saving Rollback

This is the controller code that fails to save.
def create
if params[:post_id]
#post = Post.find(params[:post_id])
#comment = #post.comments.new(comment_params)
elsif params[:issue_id]
#issue = Issue.find(params[:issue_id])
#comment = #issue.comments.new(comment_params)
end
if #comment.save
if #comment.issue_id
redirect_to Issue.find(#comment.issue_id)
elsif #comment.post_id
redirect_to Post.find(#comment.post_id)
end
else
redirect_to edit_username_path(current_user)
end
end
...
def comment_params
params.require(:comment).permit(:content)
end
And then here's the comment form:
<%= simple_form_for [#issue, #issue.comments.build] do |f| %>
<%= csrf_meta_tags %>
<%= f.input :content, required: true, input_html: { class: 'textarea', id: 'issuecommentnew' } %>
<%= f.button :submit, "Create New Comment" %>
<% end %>
if I move it around I can get it to redirect back to the issue, but no comments are saved.
Here's the params output:
{"utf8"=>"✓", "authenticity_token"=>"gNiPWM8IMa25LC0qKZ1WPnGbW4rnRCXXZficHoSM/b+t4jdcNVPS3xn4/PGjam/QiJPdMjluilIw32E2KafXJQ==", "comment"=><ActionController::Parameters {"content"=>"hello"} permitted: false>, "commit"=>"Create New Comment", "controller"=>"comments", "action"=>"create", "issue_id"=>"1"}
And the comment model:
class Comment < ApplicationRecord
belongs_to :post
belongs_to :user
belongs_to :issue
after_commit :create_notifications, on: :create
private
def create_notifications
Notification.create do |notification|
notification.notify_type = "post"
notification.actor = self.user
notification.user = self.post.user
notification.target = self
notification.second_target = self.post
end
end
end
And in the schema:
create_table "comments", force: :cascade do |t|
t.text "content"
t.integer "post_id"
t.string "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "issue_id"
end
I've included:
comment_params.merge(user: current_user, post: 0) and issue: 0
And
ActiveRecord::RecordInvalid - Validation failed: Post must exist, User must exist:
went to
ActiveRecord::AssociationTypeMismatch - Post(#70348245809340) expected, got 0 which is an instance of
solved:
issue: Issue.new
The problem is that you're missing an associated post and user. You'll have to either make sure both exist, and pass in a valid post_id and user_id, or do:
belongs_to :post, optional: true
belongs_to :user, optional: true
You're currently merging an id of 0 for both, which could never belong to a valid record of either type.

fields_for not saving nested parameters in rails 5.0.1

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.

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