Rails - Edit data on front-end like in Linkedin's profiles pages - ruby-on-rails

Is it possible, in a RoR web application, to allow users to edit elements which are in a Show page?
The target would be something like on Linkedin, when you edit your own profile page (moving your mouse over a field gives you the ability to edit it). How do they manage to do that? Is it on a Show page or an Edit page? What kind of front-end technology do we need?
I'm not a big fan of the traditional 'Edit.html' vs 'Show.html'.
Many thanks! :)

Yes you can use your show page as an edit page. You could set up your controller to something comparable to this:
your_controller.rb
class YourController < Application Controller
before_filter :show_user
def show
render :edit
end
def edit; end
private
def show_user
#user = current_user
end
end
Also don't forget your 'update' method within this controller and params that you are passing. Then you can create your edit.html view that acts as a show page, but allows edits to take place. As far as editing comparable to LinkedIn, you can use the 'best_in_place' gem for inline editing. Found here: https://github.com/bernat/best_in_place

Related

Rails. Different application layouts for different parts of the site.

I'm building a web site with a part that users can browse and administrative panel. How can use different application layouts for different parts of the site? Is it possible?
You can use layout method to render different layout for different controllers.
class MyController < ApplicationController
layout :admin_layout
private
def admin_layout
# Check if logged in, because current_user could be nil.
if logged_in? and current_user.is_able_to('siteadmin')
"admin"
else
"application"
end
end
end
You can use seperate views, for example if your run rails g controller home index you get a home_controller.rb and in the views folder you get a home folder with an index view. In your controller you can put your logic there and present it in the view.
Check this link seems to be good for beginners

redirect_to(:back) same part of page?

I have a social feed.
If the user scrolls down a lot it is annoying to the user that by liking/commenting he is redirected to the top of the page instead of in the same part of the page to where he had scrolled to.
Is there any way to do this? Otherwise I'll just use paginate to make the pages smaller, which isn't ideal because that also takes away from user friendliness.
class ActivitiesController < ApplicationController
def index
#activities = Activity.order("created_at desc").where(user_id: current_user.following_ids)
end
def show
redirect_to(:back)
end
end
I've been on a roll with questions please check them out if you have time :)
Assuming that is being redirected to the top of the page because the page is being reloaded after a comment/favorite, you could try performing these actions using ajax instead.
This way, the page won't reload and you can modify the DOM to reflect the user's actions with javascript.
Here's some more information on ajax in rails:
http://guides.rubyonrails.org/working_with_javascript_in_rails.html
First generate anchors in your page by giving them ids. For example:
<div id="activity5">
..
</div>
Then in your controller, redirect to that part by using an anchor option:
redirect_to(request.env["HTTP_REFERER"] + '#activity5')
Note: redirect_to(:back) is the same as redirect_to(request.env["HTTP_REFERER"])
Having said that, using Javascript and AJAX is probably a better option.

Rails - ability to link directly to views that are rendered via ajax

Looking for the best way to implement this. Currently I have a "show" page for Users - that shows all of a users' pictures.
def show
#user = User.find(params[:id])
#pictrues = #user.pictures
end
On that page, I have various tabs. When a user clicks on one of those tabs, an ajax call renders a view... particularly, it updates a partial that was previously showing all of a users pictures (and an additional partial for statistics). For the "show comments" example, it updates the partial with all of the pictures a user has commented on:
def show_comments
#user = User.find(params[:id])
#pictures = #user.picture_comments.map{ |p| p.picture }.uniq
respond_to do |format|
format.html
format.js
end
end
The show_comments.js.erb file looks like:
$("#user_content_container").html("<%= escape_javascript render(partial: 'shared/pictures', pictures: #pictures) %>");
$("div.user_header").html("<h4>Comments</h4><br/>");
$("#stat_container").html("<%= escape_javascript render(partial: 'shared/comment_stats', pictures: #pictures) %>");
What I want to do, is to keep the current functionality of the page. But also be able to link directly to the views that are rendered via ajax. For example, have a link on another page that goes directly to the users "show" page, as it is when the "comments" tab is clicked on.
I have a few ideas, but an not sure what the "cleanest" way of doing this would be. Let me know if you need any additional clarification, b/c I'm honestly having as difficult time wording this question, as I am in finding the best way to implement this!
This sounds like something that you might be able to solve using turbolinks. If you can update your app to use Rails 4, you get this bundled in. Otherwise, you can use the gem. For more information on how to do this, watch the railscast on turbolinks.
If you don't want to or can't use them, you could also try passing params in the url, and check for them when the page is loaded. You could use the params to modify the page in the same way that it would be modified after the AJAX call.

How to go 'back' 2 levels?

From the list view of my app, I can view a list of records or drill down and edit/update a record. After updating, I want to go directly back to the list view, bypassing a couple of intermediate pages - but I don't simply want to link_to(:action => list) - there's pagination involved. I want to go back to the exact 'list' page I came from. What's the best way? Pass a hidden arg somewhere with the page number? Is there an elegant way to accomplish this?
I'm just going to throw this one out there with the disclaimer that there may be security considerations or existing gems.
On your edit action, you could store the previous page in a session. Then in your update action, redirect to it.
class MyController < ApplicationController
def edit
session[:prev_url] = request.referer
end
def update
redirect_to session[:prev_url]
end
end
As an alternative to use the session, you could carry the referer through the actions using a hidden form field.
class MyController < ApplicationController
def edit
#prev_url = request.referer
end
def update
redirect_to params[:prev_url]
end
end
Form using hidden_field:
f.hidden_field :prev_url, :value => #prev_url
If you do not want to carry along the whole referer url you could also do the same with the page parameter instead and append the parameter to the url in the update action. I would also expect Rails' url helpers to accept parameters.

Rails Sub-controllers?

I'm pretty new to Rails and have an issue which I can't quite get my
head around as to the architecturally 'correct' way of doing it.
Problem relates to what I kinda call sub-controllers. The scenario is
this:
I have a series of pages, on which is a panel of some form containing
some information (think the user panel on gitHub top right).
So, in my app, I have controllers that generate the data for the pages
and render out the responses which is fine, but when it comes to this
panel, it seems to me that you would want some sort of controller action
dedicated to generating this panel and it's view.
Question is, how do you go about doing this? How do I render a 'sub
controller' from within a view?
I would put the logic in a helper or a module. (http://api.rubyonrails.org/classes/ActionController/Helpers/ClassMethods.html)
Then render partials where you want these things displayed. (http://api.rubyonrails.org/classes/ActionView/Partials.html)
Like Herman said, if it's logic that you need generated after the controller hands off to the view (ie, the Pages controller generates a page view, but you want a customized panel) then put it in a helper. Or, call a separate method in your Pages controller before handing off to the view. Or, if it's a lot of logic, create a Module and stick it in your /lib folder. So you could have a whole Panel module with methods that generate different parts of your Panel and which are called by your controller. But if you want to call these methods from within the view, then you should use a helper instead.
I dont think a module is what is required here, modules are required for shared behaviour across a small subset of your classes.
What I think is required here is the understanding of the inheritance of ApplicationController and also layouts
so, for example, my layout might look like:
<html>
<head><title>Foo</title></head>
<body>
<%= render :partial => (current_user ? "/shared/user_widget_bar" : "/shared/login_bar") %>
<%= yield %>
</body>
</html>
Any code that i want to use for it would go in my ApplicationController since it would be shared across the majority of my app:
before_filter :generate_user_widget
def generate_user_widget
if current_user
#avatar = ...
#unread_messages = ...
end
end
I understand that it might be cleaner for it to belong in a separate controller BUT honestly, unless the code is huge, it doesn't matter and can even still be put inside a module which is then included by ActionController. However it does need to be inside ApplicationController if you consider the scope of it.
If there are more related pages, say for example, you have a Rails app that manages multiple sites and you want shared behaviour across a particular site, try creating a parent controller which has no actions and only private methods, any controllers that need to have access to those methods can inherit off it. That way you can apply before filters to all controllers which inherit off it, saving you the pain of forgetting to add one in your non-parent controllers.
e.g:
class SiteA::SiteAParentController < ApplicationController
before_filter :generate_user_widget
...
end
class SiteA::ProductController < SiteA::SiteAParentController
def index
...
end
end
well, if you really need to call a controller action from the view, you can use components. They were part of the framework, now they only exist as plugins. One such plugin that seems to be well maintained is here: http://github.com/cainlevy/components/tree/master
from its docs:
== Usage
Note that these examples are very simplistic and would be better implemented using Rails partials.
=== Generator
Running script/generator users details will create a UsersComponent with a "details" view. You might then flesh out
the templates like this:
class UsersComponent < Components::Base
def details(user_or_id)
#user = user_or_id.is_a?(User) ? user_or_id : User.find(user_or_id)
render
end
end
=== From ActionController
class UsersController < ApplicationController
def show
return :text => component("users/detail", params[:id])
end
end
=== From ActionView
<%= component "users/detail", #user %>

Resources