I am looking for some pointers on getting started with this feature; I would like a user to be able to preview what their post would look like if saved
ActiveAdmin.register Post do
permit_params :comments, :title, :category_id, :slug, :published
# Create Blog Post
form do |f|
inputs 'Blog' do
f.semantic_errors
f.input :title
f.input :category_id, as: :select, collection: Category.all
f.input :comments, as: :text, input_html: { rows: 10, cols: 10 }
f.input :published, as: :boolean
end
inputs 'Submit' do
f.actions
end
end
end
So looking at the active admin documentation I can see you can add custom action items
action_item :preview, only: :new, name: 'preview_button' do
# do stuff here
end
I can also add a custom controller action in the form of a collection_action which will also add a route for me
collection_action :preview, method: :post do
#post = Post.new(params[:post])
end
So now I have a custom action preview and a button that can pass data to the method (I have hard coded it for now, as unsure how to get the data from outside the form).
This is what I have so far:
action_item :preview, only: :new, name: 'preview_button' do
link_to 'Preview', preview_my_admin_panel_posts_path(post: { title: 'Test Title', comments: 'test comments', category_id: '1' })
end
# Add controller action
collection_action :preview, method: :get do
#post = Post.new(params[:post_params])
end
My view gets rendered but nothing gets outputted, how do I then show the data?
Is this the correct approach?
Update
Can now show the hardcoded data with
collection_action :preview, method: :get do
#post = Post.new(permitted_params[:post])
end
The difference being in the active admin docs
The permit_params call creates a method called permitted_params. You should use this method when overriding create or update actions:
Now I just need to grab the form data outside the form and pass it through my link_to and then be able to keep the form populated with the same data if I go back to the form.
Ideally I would like to have the preview button within the f.actions as then I would have access to the #post object.
Related
I have a simple app where users will be able to purchase items. On item pages there will be an add to cart button. The carts-controller displays the items using REDIS relationship, it has no model. Once the user has reviewed the items and wishes to buy, they will be directed to purchases view where once they pay with stripe, an order will be created in purchases-controller. The purchases controller also has no model.
The user.rb model:
class User < ActiveRecord::Base
has_many :orders
def get_cart_items
cart_ids = REDIS.smembers "cart#{id}"
Item.find(cart_ids)
end
def purchase_cart_items!(recipient_name:, recipient_address:)
get_cart_items.each { |item| purchase!(item, recipient_name, recipient_address) }
REDIS.del "cart#{id}"
end
def purchase!(item, recipient_name, recipient_address)
self.orders.create!(user_email: self.email,
item_id: item.id,
recipient_name: recipient_name)
recipient_address: recipient_address)
end
end
The purchases-controller:
class PurchasesController < ApplicationController
def create
Stripe::Charge.create(
...
)
##########
current_user.purchase_cart_items!(recipient_name:, recipient_address:)
##########
end
end
The carts-controller:
class CartsController < ApplicationController
def create
REDIS.sadd current_user_cart, params[:item_id]
end
def destroy
REDIS.srem current_user_cart, params[:item_id]
end
end
Creating the Order attributes of user_email: and item_id: is easy by calling self.email and item.id since they are attached to a model, but I am unsure of how to use a form in the carts view to have the user input the recipient_name: and recipient_address: arguments for purchase_cart_items!(recipient_name:, recipient_address:) method in the purchases-controller.
I need to:
Create a form in the carts view where the user can input arguments for a method in another controller
Upon submission of the form details, I need the user to be redirected to purchases view
The form information has to be then passed as an argument to a method in the purchases-controller
Thanks!
A form_tag with a GET method needs to be used in order to submit the form info to the right controller.
In the carts view:
<%= form_tag({controller: "purchases", action: "new"}, method: "get") do %>
<%= label_tag 'recipient name: ' %>
<%= text_field_tag 'recipient_name' %>
<%= label_tag 'recipient address: ' %>
<%= text_field_tag 'recipient_address' %>
<%= submit_tag "PAY" %>
<% end %>
Once in the new action of the purchases-controller I used params to get the form info and session to make the form information available to the create action in the same controller:
class PurchasesController < ApplicationController
def new
#name = params[:name]
#address = params[:address]
session[:name] = #name
session[:address] = #address
end
def create
Stripe::Charge.create(
...
)
##########
#name = session[:name]
#address = session[:address]
current_user.purchase_cart_destinations!(name: #name, address: #address)
##########
end
end
Once the form information was accessible in the create action of purchases-controller, the keyword arguments for current_user.purchase_cart_items! were easy to set with instance variables of #name and #address.
View:
%input{type: 'submit', action: 'home#create_user'}
Controller:
class HomeController < ApplicationController
def index
render 'home/index'
end
def sign_up
render 'home/sign_up'
end
def create_user
render 'dashboard/dashboard'
end
end
routes.rb
post 'home/create_user' => 'home#create_user', :as => :create_user
Why is this button not hitting the controller?
By itself, an submit tag isn't going to generate the form. I tried your code above and the button doesn't do anything. Unless I'm forgetting INPUT doesn't have an ACTION attribute.
If you had a link to that page, the reason it's not working is because by default that link will be a GET request and you've restricted the route to POST.
So, either wrap it up in a form or use button_to or the :method => :post solutions to make it POST the request and it should work.
Something like this:
= button_to 'click me', create_user_path
= link_to 'click me', create_user_path, method: 'post'
Let's say I have book model, book.rb
class Book
include Mongoid::Document
field :book_id, type: String
field :title, type: String
end
(Here I'm using mongoid, but I think for this question it doesn't matter what type of data is.)
The book model has its own controller, views, etc.
Now, I want to create a page with form_tag (let me know if this is not a proper way), where by entering book's id and clicking enter I'll be able to remove the record this this given id from the database.
remove.html.erb:
<%= form_tag books_path, :method => 'get' do %>
<p>book_id:
<%= text_field_tag :book_id, params[:book_id] %>
<%= submit_tag "Remove", :name => nil, :confirm => "Are you sure?" %>
</p>
<% end %>
I know how to remove a given document, but can't figure out how to pass the value entered in the form and where to put the logic that will remove document.
First things first. Why do you need to store a book_id for your Book model ? Mongoid already provide a _id field for this purpose.
The usual way to destroy resources is to hit the destroy action in your controller by making a DELETE HTTP request.
class BooksController
def destroy
Book.find(params[:id]).destroy
redirect_to :back
end
end
Then simply do a link with the following:
link_to "Delete", book_path(#book), method: :delete
Where #book is your book instance.
I am relative newbie to all this, so sorry if this sounds mad!
I have used this tutorial: http://www.railsmine.net/2010/03/rails-3-action-mailer-example.html
And I have a new contact form working great.
The controller is at app/controllers/support_controller.rb
class SupportsController < ApplicationController
def new
# id is required to deal with form
#support = Support.new(:id => 1)
end
def create
#support = Support.new(params[:support])
if #support.save
redirect_to('/', :notice => "Support was successfully sent.")
else
flash[:alert] = "You must fill all fields."
render 'new'
end
end
end
And the model at /app/models/support.rb
class Support
include ActiveModel::Validations
validates_presence_of :email, :sender_name, :support_type, :content
# to deal with form, you must have an id attribute
attr_accessor :id, :email, :sender_name, :support_type, :content
def initialize(attributes = {})
attributes.each do |key, value|
self.send("#{key}=", value)
end
#attributes = attributes
end
def read_attribute_for_validation(key)
#attributes[key]
end
def to_key
end
def save
if self.valid?
Notifier.support_notification(self).deliver!
return true
end
return false
end
end
The views however only work in views/supports/new.html.rb (rendered - views/supports/_form.html.erb)
So I can call the Model / Controller from localhost:3000/support/new but if I try and render the same form in another view from the root directory e.g. app/view/contact.html.erb I get:
undefined method `model_name' for NilClass:Class
I think this is because it is calling the support model away from the supports directory.
Do I have to create an instance on #support so it can be called? If so what is the best way of doing that? I think I am nearly there. I just want the contact form on multiple pages not just in suppport/new
Thanks
Charlie
Yes, you would need to create a #support variable in each action you wish to render your form.
Another option would be to refactor the form to take a parameter, that way you're a bit more flexible. For example, from your view:
<%= render :partial => "supports/form", :locals => {:support => #support} %>
Now, instead of referring to #support in your _form.html.erb, you'd refer to simply support as it's a local_assign.
Yet another option would be to refactor the form a little further, and worry about creating the actual form tag outside of the partial.
Such as:
app/views/supports/new.html.erb
<%= form_for #support do |form| %>
<%= render :partial => "suppports/form", :object => form %>
<% end %>
app/views/supports/_form.html.erb
<%= form.text_field :foo %>
<%= form.text_field :bar %>
...
In this case, when you render a partial with the object option, you will get a local variable in your partial with the same name as the partial. You maintain a little bit more flexibility in the path of your form, but can still render the meat of what a Support object is inside of the form while remaining consistent across your app.
To clarify, you could use this somewhere else by doing something like:
app/views/foos/_create_foo_support.html.erb
<%= form_for #foo.support do |form| %>
<%= render :partial => "supports/form", :object => form %>
<% end %>
You have to pass #support object wherever you use your contact form. It's working in SupportsController#new because you initialize the variable there. In all other places where you want to use the form, you'll have to do the same.
I am using Ruby on Rails 3 and I would like to change its conventional behavior on posting a form in order to post from a signup action to the create action instead that from the new action. That is, I would like to use the signup action instead of the (conventional) new action in my User controller and trigger the create action to save my model data that contains nested resources.
In my /config/routes.rb file I have:
resources :users do
collection do
get 'signup'
end
resource :profile
end
In my /app/controllers/users_controller.rb I have
class UsersController < ApplicationController
def signup
#signup_user = User.new(params[:user])
#signup_user.build_profile # NOTE: Nested resource
...
end
def create
...
#signup_user.save
respond_to do |format|
format.html { render :action => :signup } # signup.html.erb
end
end
end
In my /app/views/users/signup.html.erb file I have
<%= form_for #signup_user do |f| %>
...
<% end %>
My problem is that if I submit the above form, I will be redirected to the index action of the user controller and not to the create action I expect. It seams that the form posts only to the index action.
How can I solve the problem?
I tryed to use the following
<%= form_for( :user, #signup_user, :url => { :controller => "users", :action => "create" }, :html => { :method => :post } do |f| %>
but I have still the problem: I am redirected to the index action.
SOLUTION
The problem did seam to be in the routers.rb. The correct code was
resources :users do
collection do
get 'signup'
post 'create'
end
resource :profile
end