So far I have two models, user and profile
Class User < ActiveRecord::Base
has_one :profile
accepts_nested_attributes_for :profile
Class Profile < ActiveRecord::Base
belongs_to :user
On my active admin model
form do |f|
f.inputs "User" do
f.input :email
#code to get the profile data
end
f.action :submit
end
So I want to get the profile data on the user form I have tryed couple of things but I wasn't able to get them.
Something like
f.inputs 'Profile', :for => [:profile, f.object.profile || Profile.new] do |profile_form|
profile_form.input ...
...
end
inside the f.inputs "User" block should work. Just set up the attributes of Profile inside this block using profile_form.
Related
Im trying to add functionality to my Rails 4 app which allows a user (who creates a project) to invite others to join their project team.
I found this tutorial, which I've found helpful: https://coderwall.com/p/rqjjca/creating-a-scoped-invitation-system-for-rails
To this point, I have the following set up:
User
has_one :profile, dependent: :destroy
Profile
belongs_to :user
has_many :teams, foreign_key: "team_mate_id"
has_many :team_projects, through: :teams, source: :project
has_many :invitations, :class_name => "Invite", :foreign_key => 'recipient_id'
has_many :sent_invites, :class_name => "Invite", :foreign_key => 'sender_id'
Project
belongs_to :profile
has_one :team
has_many :team_mates, through: :team
has_many :invites
Invite
belongs_to :project
belongs_to :sender, :class_name => 'Profile'
belongs_to :recipient, :class_name => 'Profile'
Team
belongs_to :project
belongs_to :team_mate, class_name: "Profile"
In my form, I have:
<%= simple_form_for(#invite, :url => invites_path) do |f| %>
<%= f.hidden_field :project_id, :value => #invite.project_id %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.input :expiry, :as => :date_picker, :label => "When do you need a response to this invitation?" %>
<%= f.submit 'Send' %>
<% end %>
Then in my show (rendered on the projects show) I have:
<%= render :partial => 'projects/invite_team_mate' %>
In my invites controller, I have:
class InvitesController < ApplicationController
def new
#invite = Invite.new
end
def create
#invite = Invite.new(invite_params)
#invite.sender_id = current_user.profile.id
if #invite.save
#if the user already exists
if #invite.recipient != nil
#send existing user email invitation to join project team
InviteMailer.existing_user_invite(#invite).deliver
#Add the user to the user group - inivte rsvp pending
#invite.recipient.project.push(#invite.project)
else
#send new user email invitation to join as a user and this project team
#invite.recipient.project.push(#invite.project)
# InviteMailer.new_user_invite(#invite, new_user_registration_path(:invite_token => #invite.token)).deliver
end
else
# oh no, creating an new invitation failed
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_invite
#invite = Invite.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def invite_params
params[:invite].permit(:email)
end
end
I can't figure out what else needs to happen to make this work.
When I save all this and try to invite an email address, I get this error:
undefined method `project' for nil:NilClass
That happens despite the form I use to send the invite being shown on the projects show page.
You need to add project_id and recipient_id to your invite_params, and add the recipient to your form (as a text_field, or hidden field, depending on your use case):
# controller
def invite_params
params[:invite].permit(:email, :project_id, :recipient_id)
end
# form
<%= simple_form_for(#invite, :url => invites_path) do |f| %>
...
<%= f.hidden_field :recipient_id, :value => get_recipient_id %>
...
<% end %>
Error is due to #invite.project_id, because #invite has no data so it's throwing error
<%= f.hidden_field :project_id, :value => #invite.project_id %>
replace this with or with some other desired logic
select_tag "people", options_from_collection_for_select(#projects, "id", "name")
In controlller
def new
#invite = Invite.new
#projects = current_user.team_projects // here you have to add your logic, for which project you want to invite or let me know
end
I'm finding following code very strange
if #invite.recipient != nil
...
#Add the user to the user group - inivte rsvp pending
#invite.recipient.project.push(#invite.project)
else
#send new user email invitation to join coalfacer and this project team
#invite.recipient.project.push(#invite.project)
...
end
How is that you call the same code #invite.recipient. even if #invite.recipient is Nil?!
By the way, ensure you understand why this code is written for in the controller, what it means
def invite_params
params[:invite].permit(:email)
end
For your convenience, refrain from coping code you don't understand. Also, even if you do so, do that in small portions and try after each one, so you can localize the error if any. Working in small increments is essential. You can't do a horde of changes and then just ask "what's wrong about his plenty of code".
Finally, I suggest you write specific questions, using MCVE principle. You have to extract specific portions of your code relevant to the issue, and be specific on the problem. If you put whole bunch of code, including irrelevant one, it's much much harder to help.
I am having 2 problems.
1) formtastic will only show the last input field instead of all of them. In this case it will only display:
r.input :sort_order
2) I had to do some wierd wrap f.inputs around each field to get it to show up which i believe is the wrong way. But when i submit the form it says Unpermitted parameters: page. When I did clearly define page I dont know how else to get permit params accept this.
Here is my model
class Fact < ActiveRecord::Base
has_one :page, as: :pageable, dependent: :destroy
accepts_nested_attributes_for :page
end
The other model:
class Page < ActiveRecord::Base
belongs_to :pageable, polymorphic: true
end
My active admin:
ActiveAdmin.register Fact do
permit_params :id, page_attributes: [:type, :name, :description :sort_order ]
form do |f|
f.inputs "My Page", for: [:page, f.object.page || Page.new] do |r|
r.input :name
r.input :description
r.input :sort_order
end
end
end
I can't get ActiveAdmin to save the associated model when the initial model is saved.
I have two models that look like this:
# app/models/account.rb
class Account < ActiveRecord::Base
has_one :endpoint, inverse_of :account, class_name: 'Abcd::Endpoint'
accepts_nested_attributes_for :endpoint
delegate :access_key, to: :endpoint
end
# app/models/abcd/endpoint.rb
class Abcd::Endpoint < ActiveRecord::Base
attr_accessible :account_id, :access_key
belongs_to :account
end
My ActiveAdmin file looks like:
# app/admin/account.rb
Activeadmin.register Account do
form do |f|
f.inputs do
f.input :name
end
f.inputs title: 'endpoints', for: [:endpoint. f.object.endpoint || Endpoint.new] do |nested_form|
nested_form.input :access_key,
label: 'Access Key',
as: :string
end
f.actions
end
show do |account|
row 'endpoint has access_key' do
account.access_key
end
end
end
When I click on "Update Account" the Account gets updated but the Endpoint
model doesn't get updated. It appears that the Endpoint attributes aren't
being sent to the Endpoint model.
Does anyone know how to get the Endpoint model to get updated with its
attributes or what I need to fix?
give it a try
form do |f|
f.inputs "Account" do
f.input :name
end
f.inputs do
f.has_one :endpoint, inverse_of :account, class_name: 'Abcd::Endpoint' do |nested_form|
nested_form.input :access_key,
nested_form.label('Access key')
end
end
f.actions
end
I've these two models
class Case < ActiveRecord::Base
belongs_to :client, :class_name => 'User'
end
class User < ActiveRecord::Base
has_one :requested_case, :class_name => 'Case', :foreign_key => :requested_case_id
end
and I want to create adminstration Interface for Case model using Active Admin, so when I create new case I can create new client for it in the same time, so I wrote the following lines of codes in the app/admin/cases.rb file
ActiveAdmin.register Case do
form do |f|
f.inputs "Basic Details"
f.input :title
f.input :Description
end
f.inputs :name => "Client Details", :for => :client do |c|
c.input :name
c.input :mobile
end
f.buttons
end
end
so when I filed the inputs of client and click submit I got this error
ActiveRecord::AssociationTypeMismatch in Admin::CasesController#create
User(#-625154418) expected, got ActiveSupport::HashWithIndifferentAccess(#82665960)
so any help please what's missing here?
Just add to your app/admin/cases.rb file
controller do
def new
#case = Case.new
#case.build_client
end
end
and don't forget to add accepts_nested_attributes_for to your case model
accepts_nested_attributes_for :client
I have a projects resource that has many tasks. I want to ensure that every task has a project_id by adding validates_presence_of :project_id to the tasks model.
However, when creating a new project with tasks, the project_id won't be available until the record saves, therefore I can't use validates_presence_of :project_id.
So my question is, how do I validate presence of project_id in the task model? I want to ensure every task has a parent.
...
class Project < ActiveRecord::Base
has_many :tasks, :dependent => :destroy
accepts_nested_attributes_for :tasks, :allow_destroy => true
...
class Task < ActiveRecord::Base
belongs_to :project
validates_presence_of :project_id
Your code works:
If you validates_presence_of :project, then as long as the project is there, it will validate. But if your project is unsaved, you could still save the task.
If you validates_presence_of :project_id, then the integer must be there, indicating a saved value.
Here's rSpec that proves the point. If you validate :project_id, you can't save a task without saving the Project.
class Task < ActiveRecord::Base
belongs_to :project
end
/specs/model_specs/task_spec.rb
require File.dirname(__FILE__) + '/../spec_helper'
describe Task do
before(:each) do
#project = Project.new
end
it "should require a project_id, not just a project object" do
task = Task.new
task.project = #project
Task.instance_eval("validates_presence_of :project_id")
task.valid?.should == false
end
it "should not be valid without a project" do
task = Task.new
task.project = #project
Task.instance_eval("validates_presence_of :project")
task.valid?.should == false
task.save.should == false
end
end
See here for the definitive answer :
class Project < ActiveRecord::Base
has_many :tasks, :dependent => :destroy, :inverse_of => :project
accepts_nested_attributes_for :tasks, :allow_destroy => true
class Task < ActiveRecord::Base
belongs_to :project
validates_presence_of :project
Not so elegant if you ask me... It should transparently validate.
Maybe I don't understand something, but it looks like you are trying to cheat rails. Why don't you just do like this:
class Task < ActiveRecord::Base
belongs_to :project
validate_presence_of :project
end
Take a look at this:
https://rails.lighthouseapp.com/projects/8994/tickets/2815-nested-models-build-should-directly-assign-the-parent
One thing I have done in the past is add: validates_presence_of :parent_id, :on => :update. Not great but it helps tighten the net a little.
I think you're having the same issue I dealt with. I have two models, Account and User, and when the account is created the first user is created through a #account.users.build. The User model has a validates_presence_of :account validation.
To make the first user pass validation, I added the following code to my Account model:
before_validation_on_create :initialize_users
def initialize_users
users.each { |u| u.account = self }
end
In reality you need both:
validates_presence_of project
validates_presence_of project_id
That way the task will not be saved in either of the following cases assuming that you have only 2 valid projects in the database, i.e. project id 99 is invalid:
task.project_id = 99
task.save
task.project = Project.new
task.save
I hope this is of help to someone.
Your Project class must define
accepts_nested_attributes_for :tasks
See Nested Model Form on Railscasts for more details on how to make the form.
EDIT:
In your form you should have something like this:
_form.html.erb
<% form_for #project do |f| %>
# project fields...
<% f.fields_for :tasks do |builder| %>
<%= render 'task_fields', :f => builder %>
<% end %>
<p><%= link_to_add_fields "Add task", f, :tasks %></p>
<%= f.submit %>
<% end %>
_task_fields.html.erb
<%= f.label :name, "Task name:" %>
<%= f.text_field :name %>
# task fields...
<%= link_to_remove_fields "Delete task", f, :tasks %>
link_to_add_fields and link_to_remove_fields are methods defined in application_helper to add/delete fields dynamically.