I'm learning to use padrino with haml and I get this weird behaviour while working with remote forms. The partial used for creation of an element works like a charm but the one used after the update renders in plaintext. I'm sure its a rookie mistake but I can't seem to find it.
#user.rb
get :show, :with => :id do
#user = User.get(params[:id].to_i) #REWRITE
#posts = #user.posts
session[:user_id] = #user.id
render 'user/show'
end
#post.rb
put :update, :with => :id, :provides => :js do
#post = post.first(:id => params[:post][:id].to_i, :user_id => session[:user_id].to_i)
#post.attributes(:name => params[:post][:name], :up => params[:post][:up],
:down => params[:post][:down])
if #post.save
render 'post/update'
end
end
#show.haml
#show
.user
.title= link_to #user.login, url_for(:user, :show, :id => #user.id)
.date= time_ago_in_words(#user.created || Time.now) + ' ago'
.password= #user.password
#posts= partial 'post/list', :locals => { :posts => #user.posts }
#_post.haml
.post{:id => "post#{post.id}"}
.name= post.name
.date= time_ago_in_words(post.created || Time.now) + ' ago'
- if post.up
.up +
- if post.down
.down -
= link_to "(x)", url(:post, :destroy, :id => post.id, :format => :js, :method => 'delete'), :confirm => "Sure?", :remote => true
= link_to "(e)", url(:post, :edit, :id => post.id, :format => :js), :remote => true
#_edit.haml
- form_for :post, url(:post, :update, :id => #post.id, :format => :js), :remote => true, :method => 'put', :id => 'post_edit_form' do |f|
= partial 'post/form', :locals => {:f => f}
= f.text_field :id, :hidden => true
= f.submit "Edit", :class => 'button'
#update.js.haml
:plain
alert("ok");
And after clicking the edit button I get a white page with: alert("ok"); why is the update.js.haml page not rendered as remote js?
WEBrick log:
DEBUG - TEMPLATE (0.0003s) /habit/update.js
DEBUG - PUT (0.0170s) /habit/update/1.js - 200 OK
Sorry for leaving issues like these unattended for so long.
The issue you're having there is that update.js.haml is instructing Haml to render it as plain text and not inside a script tag. That's why the browser would never run it; you should be using :javascript instead, as follows:
#update.js.haml
:javascript
alert("ok");
In any way, most times you will want to reference external assets, i.e., real JS files. If you need to bootstrap those with some data at load time you can look at alternatives such as injecting a script tag containing a variable that will set the initial data and consume it in your application (there are different ways of doing this). Alternatively, you can load that data through AJAX or WS, bear in mind that this creates more connections to the server and may have the user waiting, so it's not a good approach if the data needs to be ready at load if, say, you're building an SPA.
Related
First we start off with conversations/index.html.haml to create a message
#new_message_conversation
.panel.panel-info
.panel-heading
%h4 Send a Bark!
.panel-footer(style="padding-top: 20px")
= simple_form_for :message, url: :messages, :remote => true do |f|
.form-group
= f.input :master_name, placeholder: 'Choose master...', label: false, :url => autocomplete_master_name_conversations_path, :as => :autocomplete, id_element: "#master_name_id", input_html: {class: "form-control"}
= f.input :recipient_id, as: "hidden", input_html: {id: "master_name_id"}
= f.input :body, label: false, as: "text", placeholder: 'Write message...', :input_html => { :rows => 5 }
= f.button :submit, 'Send', :class => "btn btn-lg btn-primary", :disable_with => "Sending..."
which then goes to the messages#create action which has
...
respond_to do |format|
format.js { render "create", locals: { conversation: #conversation, conversations: #conversations, receipts: #receipts }}
end
...
which sends the work to the conversations/create.js.erb file
$('#new_message_conversation').prop('disabled', true).html("<%= raw escape_javascript(render(:partial => 'conversations/show', locals: { conversation: conversation, receipts: receipts })) %>").hide().fadeIn('fast');
which adds the conversations/show partial, _show.html.haml which has
...
%ul.pager.pull-left(style= "padding-left: 10px")
%li#paginator_3= link_to_previous_page #receipts, "Newer", :remote => true, :param_name => 'page_2'
%li#paginator_4= link_to_next_page #receipts, "Older", :remote => true, :param_name => 'page_2'
...
everything works excepts now the pagination buttons don't work. and when I click a pagination button the server says
Rendered messages/index.js.erb
Why does a partial that's in views/conversations that has a remote ajax call render to a different controller (messages)? It should be rendering conversations/show.js.erb because the partial is conversations/_show.html.haml right?
here are my routes also
...
resources :conversations do
get :autocomplete_master_name, :on => :collection
end
resources :messages
...
Even though you're rendering views and partials from the conversations path, you never even touched the ConversationController.
You can render whatever views you want for the action you're executing. The only thing connecting the ConversationController with the views/conversation/file.html.erb and similar view files is a loose naming convention. When rendering say render 'index' from an action of the ConversationController, it just assumes by that convention you meant the views/conversation/index.html.erb file.
Your view or partial alone cannot reference the controller it would belong to (when going by the naming convention) because it is just used as a template by the render command in your action. The view doesn't care whether the controller behind it is the appropriate one. In this case, the render was originally executed in the MessagesController, so the view also just has a reference to that one.
To still have the links point to the correct controller, you need to specify the controller to be used for the url. Otherwise, it is assumed that you want to use the very same controller you used to render the page.
The culprit is probably somewhere in the link_to_previous_page and link_to_next_page helpers by kaminari. When using the full paginate helper, you can set the controller and action you want to use like this:
<%= paginate #users, :params => {:controller => 'foo', :action => 'bar'} %>
The documentation (here: https://github.com/amatsuda/kaminari) doesn't say whether this param is also possible with the other helpers, but the helper uses a simple link_to (see here: https://github.com/amatsuda/kaminari/blob/master/lib/kaminari/helpers/action_view_extension.rb), so you should be able to do something like this:
link_to_previous_page #receipts, "Newer", {:controller => 'foo', :action => 'bar', :remote => true, :param_name => 'page_2'}
A put custom action approve was added to our rails 3.1.3 app in sourcing controller for updating 3 parameters. Custom route was added in routes.rb and link_to was called with :method => :put. However the parameters are not reset by the 'approve'.
Here is the link_to in sourcing index.html.erb:
<% #sourcings.each do |src| %>
...
<%= link_to 'Approve', approve_project_sourcing_path(#project, src), :method => :put if need_approve?(src) %>
<% end >
need_approve? is a method defined in sourcings controller to see if the sourcing needs to be approved.
Here is the rake routes output for approve:
approve_project_sourcing PUT /projects/:project_id/sourcings/:id/approve(.:format) {:action=>"approve", :controller=>"sourcings"}
Here is the approve in sourcing controller:
def approve
#project = Project.find(params[:project_id])
#sourcing = #project.sourcings.find(params[:id])
if vp_eng?
#sourcing.update_attributes!(:approved_by_vp_eng => true, :approve_vp_eng_id => session[:user_id],
:approve_date_vp_eng => Time.now, :as => :role_update)
elsif ceo?
#sourcing.update_attributes(:approved_by_ceo => true, :approve_ceo_id => session[:user_id],
:approve_date_ceo => Time.now, :as => :role_update)
end
redirect_to project_sourcing_path(#project, #sourcing)
end
Is anything we missed in the code above? Thanks so much.
The problem is with the way to call update_attributes. With hash parameters, the correct syntax is :
#sourcing.update_attributes({:approved_by_vp_eng => true, :approve_vp_eng_id => session[:user_id],:approve_date_vp_eng => Time.now}, :as => :role_update)
A brace bracket is needed for the hash parameters.
I am having some problems with link_to remote sending a post to another controller... The result are not quite what I expect..
I have this in node_content.html.erb:
<% #node.videos.each do |vid| %>
<div id="vid_vid"><%= link_to image_tag("http://img.youtube.com/vi/#{vid.content}/1.jpg"), :controller => 'videos', :action => "iframize", :video_id => vid.id, :method => :post, :remote => true %></div>
<% end %>
And I have this in videos_controller:
def iframize
#video = Video.find(params[:video_id])
respond_to do |format|
format.js
end
end
And this in routes:
resource :videos do
collection do
post 'iframize'
end
end
Problem is that when I click the link, it takes me to
http://localhost:3000/videos/iframize?method=post&video_id=20
and I get
Couldn't find Video with id=iframize
I looked through tens of various examples and they seem to recommend the above, but it does not work.. What am I doing wrong?
Any input greatly appreciated!
Thanks!
EDIT:
I tried this approach jquery function and it kinda worked (only for the first video in the loop of course):
<% #node.videos.each do |vid| %>
<%= image_tag("http://img.youtube.com/vi/#{vid.content}/1.jpg", :id => 'img_div') %>
<div id="vid_vid"> <%= vid.id %></div>
<% end %>
$('#img_div').on({
'click': function() {
var vid_id = document.getElementById("vid_vid").innerHTML;
$.post("/videos/iframize/", {video_id: vid_id});
}
});
Do you have rails_ujs included via jquery_ujs in assets/application.css file
= link_to image_tag("http://img.youtube.com/vi/#{vid.content}/1.jpg"), "url_path", :method => :post, :remote => true
Convert the following into a rails path: like iframeize_videos_path (generated via rake routes)
:controller => 'videos', :action => "iframize", :video_id => vid.id,
You need to differentiate the url options, html options.so use
<%= link_to image_tag("http://img.youtube.com/vi/#{vid.content}/1.jpg"),
{ :controller => 'videos', :action => "iframize", :video_id => vid.id },
{ :method => :post, :remote => true} %>
Something is seriously not adding up here.. My page just refreshes, nothing happens, it never touches any of my debuggers hanging out on all my methods except for index.
my html:
<%- for image in #images %>
<%= image.attachment_file_name %>
<%-# link_to_delete image, :url => destroy_image_admin_wysiwyg_path(image.id) %>
<%= link_to 'delete', { :url => destroy_image_image_path(image.id) },
#:confirm => 'Are you sure?',
:post => true
%>
<br />
<% end %>
my controller
def destroy_image
debugger
#img = Image.find(params[:id])
#img.destroy
respond_to do |format|
format.html { redirect_to admin_image_rotator_path }
end
end
My routes:
map.resources :images, :member => { :destroy_image => :post }
My disgusting hack that works that I will replace as soon as I find something better
I moved the action over to a simpler controller I built myself.
Changed my routes to :
admin.resources :wysiwygs, :member => { :destroy_image => :post }
Changed my html :
<%= link_to 'delete', :controller => "wysiwygs", :action => "destroy_image" %>
But when I clicked on the link..it brought up.. the show action ?? fffffffffuuuuuuu
I retaliated by just moving my action to the show action, and passing a hidden field in my html..
<%= link_to 'delete', :controller => "wysiwygs", :action => "destroy_image", :hidden_field => {:value => image.id} %>
def show
# this was previously in destroy_image
#img = Image.find(params[:hidden_field][:value])
#img.destroy
respond_to do |format|
format.html { redirect_to admin_image_rotator_path }
end
end
It seems you're going down the wrong path here. If a before_filter is blocking your action, figure out why. Use skip_before_filter :filter_name if the filter is not needed.
Don't use show actions or HTTP GET for deletes. Even if it works, it will confuse things down the road. Use a DELETE verb:
map.resources :images, :member => { :destroy_image => :delete }
pass it in the link helper:
<%= link_to "delete", destroy_image_image_path(image), :method => :delete %>
And use ImagesController#destroy_image to perform the action. Better yet, consider using the standard RESTful ImagesController#destroy which map.resources gives you for free.
Not sure what was wrong in the first place, but in your second, working solution, i think you should write your link_to as follows:
link_to 'delete', :controller => "wysiwygs", :action => "destroy_image", :id => image.id
That at least would send you to the correct action.
Depending on your routes, you will have to make this a method => :post or not.
Check your rake routes output, it will show you what are the possible routes, and also what names they got, which in turn you can use as a method (add _path or _url at the end). Then it should be even easier to write something like:
link_to 'delete', wysiwygs_destroy_image_path(image)
Good luck!
You're doing a POST but your resource says that :destroy_image is only available via GET. Try changing your route to:
map.resources :images, :member => { :destroy_image => :post }
Also, take a look at your link_to. The second parameter takes a URL, not a hash that has a :url key. As mentioned elsewhere, depending on your Rails version you may need :method => :post instead of :post => true. In Rails 2.3.8, you would want this line instead:
<%= link_to 'delete', destroy_image_image_path(image), :method => :post %>
After utilizing the great trial and error for over an hour along with dozens of tutorials and blogs posting examples, I still cannot get the simple ajax functionality to work. Here is what is in my partial:
<span id="friend">
<%= link_to_remote image_submit_tag("/images/add_as_friend.gif"), :url => {:controller => 'friends', :action => 'add', :id => id} %>
</span>
This is what is in my controller:
class FriendsController < ApplicationController
def add
unless params[:id].nil?
Friend.create(:user_id => #current_user.id, :friend_id => params[:id], :friend_type => 2)
end
end
end
This is what is in my add.rjs file:
page.replace_html 'friend', "A request to be friends with this player has been sent."
The image for the link comes up fine. When I click on it, however, nothing happens. I've checked the database and nothing is going on. I must be missing something, any thoughts?
It may be because you are using image_submit_tag rather than image_tag for the content of your link. image_submit_tag is for submitting forms so will have its own onclick behaviour which may override the onclick behaviour that will be added as part of the link_to_remote functionality.
I would try:
<%= link_to_remote image_tag("/images/add_as_friend.gif"),
:url => {:controller => 'friends', :action => 'add', :id => id} %>