I am trying to make an admin page that has a nested form for another model.
I have a Playbook model:
playbook.rb
has_and_belongs_to_many :groups
accepts_nested_attributes_for :groups
my form view
_form.html.haml
<%= form_with(model: playbook, local: true) do |form| %>
...
<%= collection_check_boxes(:group, :group_ids, Group.all, :id, :name) %>
<div class="actions">
<%= form.submit %>
</div>
To explain it more, playbooks can have many groups which are another model and I want to save to the groups_playbooks join table automatically when saving the playbook using what I think would be a nested form. I just dont know how to do the nested form with a collection of checkboxes like my view.
Here is part of schema to help give a better picture:
create_table "groups", force: :cascade do |t|
t.string "name"
t.string "variables"
t.bigint "server_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["server_id"], name: "index_groups_on_server_id"
end
create_table "groups_playbooks", id: false, force: :cascade do |t|
t.bigint "group_id", null: false
t.bigint "playbook_id", null: false
end
create_table "groups_servers", id: false, force: :cascade do |t|
t.bigint "group_id", null: false
t.bigint "server_id", null: false
end
create_table "playbooks", force: :cascade do |t|
t.string "name"
t.string "play"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "description"
end
create_table "playbooks_servers", id: false, force: :cascade do |t|
t.bigint "playbook_id", null: false
t.bigint "server_id", null: false
end
create_table "servers", force: :cascade do |t|
t.string "name"
t.string "ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "group_id"
t.index ["group_id"], name: "index_servers_on_group_id"
end
According to specification you should use playbook instead of groups
<%= collection_check_boxes(:playbook, :group_ids, Group.all, :id, :name) %>
But as you have the form builder you should look on that specification
For your case
<%= form.collection_check_boxes(:group_ids, Group.all, :id, :name) %>
Related
<div class="field">
<%= form.label :user_id%>
<%= form.collection_select :user_id, User.all, :id , :emailaddress%>
How can I modify the select to only select the email address of users with their admin role as True?
Here is my schema..
create_table "courses", force: :cascade do |t|
t.integer "coursenumber"
t.integer "user_id"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_courses_on_user_id"
create_table "users", force: :cascade do |t|
t.string "firstname"
t.string "lastname"
t.string "title"
t.integer "officenumber"
t.string "emailaddress"
t.integer "phone"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "admin"
I think you can use the where method, as you would normally:
User.where(admin: true)
<%= form.collection_select :user_id, User.where(admin: true), :id , :emailaddress%>
You also could create a scope in your model named admins, and then just call User.admins or something like that.
So I have a scaffold for both blogs and post_category.
I made an association with both of them. Here's my schema:
create_table "blogs", force: :cascade do |t|
t.string "title"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
t.integer "status", default: 0
t.bigint "post_category_id"
t.index ["post_category_id"], name: "index_blogs_on_post_category_id"
t.index ["slug"], name: "index_blogs_on_slug", unique: true
end
create_table "post_categories", force: :cascade do |t|
t.string "name"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
So simply I created a couple of post categories and when I try to make an association with blog items so whenever I create a new blog I can display a select statement and choose my preferred category for the blog item I am trying to create but I don't know how to display all categories on all forms and on the index.html.erb file:
<div class="field">
<%= form.label :category %>
<%= form.collection_select :post_category, PostCategory.all %>
</div>
How can I achieve this? And make sure that it saves the data as well?
as per this reference, the format is
collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})
and for your code, it can be like this
<%= form.collection_select(:post_category, :post_category_id, PostCategory.all, :id, :name, prompt: true) %>
update 2:
inside your blog_controllers
# white list parameter
def blog_params
params.require(:blog).permit(
:post_category_id,
... others fields
)
end
I'm new to Rails so maybe this is a stupid question. I'm struggling to get a attribute from another model in a nested form. Let me explain:
I have 3 models linked each other. Poi -> PoiDescription <- DescriptionType
One Poi can have multiple descriptions and a description have only one description type. I'm creating the PoiDescriptions inside the Poi form with a nested form. Every thing is working well, but now, inside the fields_for I want a label before the textarea with the name of the description type. But I don't know how to get it...I can't do something like 'p.description_type.name' so how can I get that attribute?
Here is my code:
Poi Controller
def new
#poi = Poi.new
#descriptions = DescriptionType.all
#descriptions.each do |d|
#poi.poi_descriptions.new(description_type_id: d.id)
end
end
Poi form
<%= form_with model: #poi do |f| %>
...
<div class="col-md-12">
<%= f.fields_for :poi_descriptions do |p| %>
<%= p.hidden_field :description_type_id %>
<%= p.text_area :description %>
<% end %>
</div>
...
Schema
create_table "description_types", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "poi_descriptions", force: :cascade do |t|
t.text "description"
t.bigint "poi_id"
t.bigint "description_type_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["description_type_id"], name: "index_poi_descriptions_on_description_type_id"
t.index ["poi_id"], name: "index_poi_descriptions_on_poi_id"
end
create_table "pois", id: :serial, force: :cascade do |t|
t.text "name"
t.float "longitude"
t.float "latitude"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "monument_id"
t.integer "beacon_id"
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.index ["beacon_id"], name: "index_pois_on_beacon_id"
t.index ["monument_id"], name: "index_pois_on_monument_id"
end
Hope you can help me! Thanks in advance.
To get from the form_builder_object to the actual object you can do p.object.description_type.name
If you just want that as a title and not as an input field you can either:
Add it in a p or span tag and make it look like a label with css or
Add a label_tag with a custom name and title as you need. https://apidock.com/rails/ActionView/Helpers/FormTagHelper/label_tag
I have two tables, accounts and items and I would like to show the buisness_name instead of the idfrom the accounts table on the view/items/show.html.erb page.
Currently I have no associations between the models, but I have the account_id column in the items table.
create_table "accounts", force: :cascade do |t|
t.string "buisness_name"
t.string "web_site"
t.string "phone_number"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "items", force: :cascade do |t|
t.string "title"
t.text "description"
t.string "image"
t.decimal "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "category_id"
t.json "attachments"
t.integer "account_id"
end
I'm getting the account_id via this: <%= #item.account_id %>, but I would like to show the buisness_name instead.
Try something like this
class Item < ActiveRecord::Base
belongs_to :account
end
Into the view
<% if #item.account %>
<%= #item.account.buisness_name %>
<% end %>
Should be business_name, as #Sergio Tulentsev already told you
I updated my answer because I noticed from the table that the account_id has not a not null constraint
If you have
<%= #item.account_id %>
The horrible way to get the account would be
<%= Account.find_by(id: #item.account_id).try(:buisness_name) %>
Much smarter would be
class Item
belongs_to :account
delegate :buisness_name, to: :account, prefix: true, allow_nil: true
And then in the view...
<%= #item.account_buisness_name %>
I have a Rails app that is supposed to allow you to create a profile after you sign up and click the "Create user Profile" link. But for some reason the below error shows up instead of my form field page.
EDIT:
Error raised:
undefined method `first_name' for #<Profile id: nil>
Showing /home/ubuntu/workspace/saasapp/app/views/profiles/_form.html.erb:
<div class="form-group">
<%= f.label :first_name %>
<%= f.text_field :first_name, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :last_name %>
Please help. I am not sure where I went wrong. I am taking a course on upskillcourses.com and I followed along with the video and I even copied the code and pasted it in to the file just in case the first two times I typed it out by hand was incorrect.
Here is the routes.rb file:
Rails.application.routes.draw do
root to: 'pages#home'
devise_for :users, controllers: { registrations: 'users/registrations' }
resources :users do
resource :profile
end
get 'about', to: 'pages#about'
resources :contacts, only: [:create]
get 'contact-us', to: 'contacts#new', as: 'new_contact'
end
Schema.rb:
ActiveRecord::Schema.define(version: 20170314180155) do
create_table "contacts", force: :cascade do |t|
t.string "name"
t.string "email"
t.text "comments"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "plans", force: :cascade do |t|
t.string "name"
t.decimal "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "profiles", force: :cascade do |t|
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "plan_id"
t.string "stripe_customer_token"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end
Looks like your Profile model doesn't have first_name field. Since you didn't get the "migration" error, I can only assume you need to add those 2 fields in a separate migration as a task in your online course...
As per OP's comments:
# Add missing columns to profiles table
rails generate migration AddFirstNameAndLastNameToProfile first_name last_name
# Run migration
rails db:migrate